import base64
import copy
import glob
import os
import random
import re
import secrets
from typing import List

import pandas

from hackingBuddyGPT.usecases.web_api_testing.documentation.parsing import OpenAPISpecificationParser
from hackingBuddyGPT.utils.prompt_generation.information.prompt_information import (
    PromptPurpose,
)
from faker import Faker


class PenTestingInformation:
    def __init__(self, openapi_spec_parser: OpenAPISpecificationParser, config) -> None:
        """
        Initializes the PenTestingInformation with optional authentication credentials.

        Args:
            openapi_spec_parser (OpenAPISpecificationParser): An instance of OpenAPISpecificationParser.
            username (str, optional): Username for authentication, if necessary. Defaults to an empty string.
            password (str, optional): Password for authentication, if necessary. Defaults to an empty string.
        """

        # Set basic authentication details
        if "admin" in config:
            self.admin = config["admin"]
        else:
            self.admin = None
        self.guest = None
        self.credentials = {}
        self.resources = {}
        self.valid_token = None
        self.current_post_endpoint = None  # TODO
        self.faker = Faker()
        self.username = self.faker.email().lower()
        self.password = self.faker.password()
        self.available_numbers = []
        self.config = config
        file = self.get_file(self.config.get("csv_file"))
        if file == "Not found":
            self.df = pandas.DataFrame()
        else:
            self.df = pandas.read_csv(file[0], names=["username", "password"])

        # Parse endpoints and their categorization from the given parser instance
        categorized_endpoints = openapi_spec_parser.classify_endpoints(self.config.get("name"))

        # Assign schema and endpoint attributes directly from the parser methods
        self.schemas = openapi_spec_parser.get_schemas()
        self.endpoints = openapi_spec_parser.get_endpoints()
        self.openapi_spec_parser = openapi_spec_parser
        self.get_comment_ep()

        # Assign categorized endpoint types to attributes
        self.assign_endpoint_categories(categorized_endpoints)
        self.accounts = []
        opt_endpoints = [ep for ep in self.endpoints if "otp" in ep]

        self.brute_force_accounts = []
        if self.admin is not None:
            admin = self.config.get("admin").get("email")
            self.assign_brute_force_endpoints(admin)

        self.pentesting_step_list = [PromptPurpose.SETUP,
                                     PromptPurpose.VERIY_SETUP,
                                     PromptPurpose.AUTHENTICATION,
                                     PromptPurpose.AUTHORIZATION,
                                     PromptPurpose.SPECIAL_AUTHENTICATION,
                                     PromptPurpose.INPUT_VALIDATION,
                                     PromptPurpose.ERROR_HANDLING_INFORMATION_LEAKAGE,
                                     PromptPurpose.SESSION_MANAGEMENT,
                                     PromptPurpose.CROSS_SITE_SCRIPTING,
                                     PromptPurpose.CROSS_SITE_FORGERY,
                                     PromptPurpose.BUSINESS_LOGIC_VULNERABILITIES,
                                     PromptPurpose.RATE_LIMITING_THROTTLING,
                                     PromptPurpose.SECURITY_MISCONFIGURATIONS,
                                     PromptPurpose.LOGGING_MONITORING
                                     ]

    def assign_endpoint_categories(self, categorized_endpoints):
        """
        Assign categorized endpoint types to instance attributes from given categorized endpoints dictionary.

        Args:
            categorized_endpoints (dict): A dictionary containing categorized endpoints.
        """
        self.resource_intensive_endpoint = categorized_endpoints.get('resource_intensive_endpoint')

        self.secure_action_endpoint = categorized_endpoints.get('secure_action_endpoint')
        self.role_access_endpoint = categorized_endpoints.get('role_access_endpoint')
        self.sensitive_data_endpoint = categorized_endpoints.get('sensitive_data_endpoint')
        self.sensitive_action_endpoint = categorized_endpoints.get('sensitive_action_endpoint')
        self.login_endpoint = categorized_endpoints.get('login_endpoint')
        self.account_endpoint = categorized_endpoints.get('account_creation')
        self.auth_endpoint = categorized_endpoints.get('auth_endpoint')
        self.generate_iter_and_assign_current_endpoints(categorized_endpoints)
        self.analysis_step_list = [PromptPurpose.ANALYSIS, PromptPurpose.DOCUMENTATION,
                                   PromptPurpose.REPORTING]
        self.categorized_endpoints = categorized_endpoints
        self.tokens = {}
        self.counter = 0

    def set_valid_token(self, token: str) -> None:
        self.valid_token = token

    def generate_iter_and_assign_current_endpoints(self, categorized_endpoints):
        for key in ['public_endpoint', 'protected_endpoint', 'refresh_endpoint']:
            endpoint_list = categorized_endpoints.get(key, [])
            if endpoint_list:
                setattr(self, f"{key}_iterator", iter(endpoint_list))
                setattr(self, f"current_{key}", next(getattr(self, f"{key}_iterator"), None))
            else:
                setattr(self, f"{key}_iterator", iter([]))
                setattr(self, f"current_{key}", None)

    def explore_steps(self, purpose: PromptPurpose) -> List[str]:
        """
        Provides initial penetration testing steps for the given purpose.

        Args:
            purpose (PromptPurpose): The purpose for which testing steps are required.

        Returns:
            list: A list of steps corresponding to the specified purpose.
        """
        # Map purposes to their corresponding methods
        purpose_methods = {
            PromptPurpose.SETUP: self.setup_test,
            PromptPurpose.VERIY_SETUP: self.verify_setup,
            PromptPurpose.AUTHENTICATION: self.generate_authentication_prompts,
            PromptPurpose.AUTHORIZATION: self.generate_authorization_prompts,
            PromptPurpose.SPECIAL_AUTHENTICATION: self.generate_special_authentication,
            PromptPurpose.INPUT_VALIDATION: self.generate_input_validation_prompts,
            PromptPurpose.ERROR_HANDLING_INFORMATION_LEAKAGE: self.generate_error_handling_prompts,
            PromptPurpose.SESSION_MANAGEMENT: self.generate_session_management_prompts,
            PromptPurpose.CROSS_SITE_SCRIPTING: self.generate_xss_prompts,
            PromptPurpose.CROSS_SITE_FORGERY: self.generate_csrf_prompts,
            PromptPurpose.BUSINESS_LOGIC_VULNERABILITIES: self.generate_business_logic_vul_prompts,
            PromptPurpose.RATE_LIMITING_THROTTLING: self.generate_rate_limit_throttling,
            PromptPurpose.SECURITY_MISCONFIGURATIONS: self.generate_security_misconfiguration_prompts,
            PromptPurpose.LOGGING_MONITORING: self.generate_logging_monitoring_prompts
        }

        # Call the appropriate method based on the purpose
        if purpose in purpose_methods:
            return purpose_methods[purpose]()
        else:
            raise ValueError(f"Invalid purpose: {purpose}")

    def get_analysis_step(self, purpose: PromptPurpose = None, response: str = "", additional_context: str = "") -> str:
        """
        Provides prompts for analysis based on the provided response for various purposes using an LLM.

        Args:
            response (str, optional): The HTTP response to analyze. Default is an empty string.

        Returns:
            dict: A dictionary where each key is a PromptPurpose and each value is a list of prompts.
        """
        if purpose == PromptPurpose.ANALYSIS:
            return f"Given the following parsed HTTP response:\n{response}\n" \
                   f"Based on this context: {additional_context}\n" \
                   "Analyze this response to determine in form of a RecordNote:\n" \
                   "1. Whether the status code is appropriate for this type of request.\n" \
                   "2. If the headers indicate proper security and rate-limiting practices. \n" \
                   "3. If the headers include sensitive information like 'Server', 'X-Powered', 'X-Frame-Options', 'Cache-Control', 'Strict-Transport-Security', 'Set-Cookie', 'X-Request-ID', 'Accept-Encoding', 'Referer', and 'X-API-Version' ALso add why this can cause a vulnerability.\n" \
                   "4. Whether the response body is correctly handled."
            # "Keep your analysis short."

        if purpose == PromptPurpose.DOCUMENTATION:
            return f"Based on the analysis provided, document the findings in form of a RecordNote:\n{response}."
            # f" Keep your analysis short."

        if purpose == PromptPurpose.REPORTING:
            return (f"Based on the documented findings : {response}.\n"
                    f"Suggest any improvements or issues that should be reported based on the findings to the API developers in form of a RecordNote.")
            # f"Keep your analysis short."

    def get_steps_of_phase(self, purpose):
        steps = self.explore_steps(purpose)
        return steps

    def next_testing_endpoint(self):
        self.current_public_endpoint = next(self.public_endpoint_iterator, None)
        self.current_protected_endpoint = next(self.protected_endpoint_iterator, None)
        self.current_refresh_endpoint = next(self.refresh_endpoint_iterator, None)

    def setup_test(self) -> List:
        prompts = []
        counter = 0
        post_account = self.get_correct_endpoints_for_method("account_creation", "POST")
        prompts, counter = self.generate_user(post_account, counter, prompts)
        if len(self.accounts) == 1:  # ensure that there are at least two users
            prompts, counter = self.generate_user(post_account, 1, prompts)

        return prompts

    def verify_setup(self) -> List:
        prompts = []

        get_account = self.get_correct_endpoints_for_method("public_endpoint",
                                                            "GET") + self.get_correct_endpoints_for_method(
            "protected_endpoint", "GET")

        get_account = [ep for ep in get_account if ep.get("path").endswith("user") or ep.get("path").endswith("login")]
        if len(get_account) == 0:
            get_account = [
                self.endpoints[path]for path, methods in self.endpoints.items()
                if path.endswith("/users/{id}") and "get" in methods
            ]

        for acc in get_account:
            for account in self.accounts:
                account_path = acc.get("path")
                account_schema = acc.get("schema")
                if "api" in account_path:
                    if account["api"] in account_path:
                        if "user" and "id" in account_path:
                            account_path = account_path.replace("{id}", str(account.get("id")))
                        prompts = prompts + [{
                            "objective": "Check if user was created",
                            "steps": [
                                f"Endpoint to use : {account_path}\n"
                                f"Send a GET request to the {account_path} with the with the correct schema {account_schema} with user:{account}.\n"
                            ],
                            "path": [account_path],
                            "token": [account.get("token")],
                            "expected_response_code": ["200 OK", "201 Created"],
                            "security": [
                                f"Ensure that the returned user matches this user {account}"]
                        }]
                else:
                    if "id}" in account_path:

                        if isinstance(account.get("example"), dict):
                            if "example" in account.keys():
                                if "id" in account.get("example").keys():
                                    account_path = account_path.replace("{id}",
                                                                        str(account_schema.get("example").get("id")))
                                else:
                                    account_path = account_path.replace("{id}", str(account_schema.get("example")))
                        else:
                            account_path = self.replace_placeholders_with_1(account_path, account.get("id"))

                    if account_schema:
                        if "Authorization-Token" in account_schema.values():
                            if "example" in account.keys() and "id" in account.get("example") and account.get(
                                    "example").get("id") not in self.tokens.keys():
                                description = account_schema.get("description") \
                                    .replace("username", account.get("example").get("username")) \
                                    .replace("password", account.get("example").get("password"))
                                account_schema["description"] = description
                                credentials = account.get("example").get("username") + ":" + account.get("example").get(
                                    "password")
                                self.tokens[account.get("example").get("id")] = base64.b64encode(
                                    credentials.encode('utf-8')).decode('utf-8')

                    prompts = prompts + [{
                        "objective": "Check if user was created",
                        "steps": [
                            f"Endpoint to use : {account_path}\n"
                            f"Send a GET request to the {account_path} with the with the correct schema {account_schema} with user:{account}.\n"
                        ],
                        "path": [account_path],
                        "token": [account.get("token")],
                        "expected_response_code": ["200 OK", "201 Created"],
                        "security": [
                            f"Ensure that the returned user matches this user {account}"]
                    }]
        for login in self.login_endpoint:
            for account in self.accounts:

                login_path, login_schema = self.get_path_and_schema(login)
                if login_schema is None:
                    continue
                login_schema = self.fill_in_schema_with_account(login_schema, account)

                if "api" in account.keys():
                    if account["api"] in login_path:
                        prompts = prompts + [
                            {
                                "objective": "Get Valid token",
                                "steps": [
                                    f"Endpoint to use : {login_path}\n"
                                    f"Send a POST request to the {login_path} with the correct credentials of user:{account}.\n"
                                    f"Request body should be in application/json and look similar to this: {{ {login_schema}}}"
                                ],
                                "path": [login_path],
                                "token": [account.get("token")],
                                "expected_response_code": ["200 OK", "201 Created"],
                                "security": [
                                    "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]
                            }
                        ]
                else:

                    if account is None:
                        account = self.create_account(login_schema, login_path)
                        if account is None:
                            continue

                    prompts = prompts + [
                        {
                            "objective": "Get Valid token",
                            "steps": [
                                f"Endpoint to use : {login_path}\n"
                                f"Send a POST request to the {login_schema} with the correct credentials of user:{account}.\n"
                                f"Request body should be in application/json and look similar to this: {{ {account}}}"
                            ],
                            "path": [login_path],
                            "token": [""],
                            "expected_response_code": ["200 OK", "201 Created"],
                            "security": [
                                "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]
                        }
                    ]

        account = None
        if len(prompts) == 0:
            for login in self.login_endpoint:
                login_path, login_schema = self.get_path_and_schema(login)
                if login_schema is None:
                    continue
                if account is None:
                    account = self.create_account(login_schema, login_path)
                    if account is None:
                        continue

                prompts = prompts + [
                    {
                        "objective": "Get Valid token",
                        "steps": [
                            f"Endpoint to use : {login_path}\n"
                            f"Send a POST request to the {login_schema} with the correct credentials of user:{account}.\n"
                            f"Request body should be in application/json and look similar to this: {{ {login_schema}}}"
                        ],
                        "path": [login_path],
                        "token": [""],
                        "expected_response_code": ["200 OK", "201 Created"],
                        "security": [
                            "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]
                    }
                ]

        return prompts

    def generate_request_body_string(self, schema, endpoint):
        """
        Generate a request body string based on the updated schema.

        Args:
            schema (dict): A schema dictionary containing an example.
            username (str): The username to populate in the example.
            password (str): The password to populate in the example.

        Returns:
            str: A formatted request body string.
        """
        updated_schema = self.get_credentials(schema, endpoint)
        example = updated_schema.get("example", {})

        # Generate key-value pairs from the schema example dynamically
        key_value_pairs = [f"'{key}': '{value}'" for key, value in example.items() if value != ""]
        return key_value_pairs

    def replace_placeholders_with_1(self, path: str, id) -> str:
        """
        Replaces any curly-brace placeholders (e.g., '{videoid}', '{orderid}', '{someid}')
        with the number '1' in the given path.

        Example:
            "/identity/api/v2/user/videos/{videoid}" -> "/identity/api/v2/user/videos/1"
            "/workshop/api/shop/orders/{orderid}"    -> "/workshop/api/shop/orders/1"
            "{somethingid}"                          -> "1"
        """

        def substitute(match):
            # Extract the placeholder from the match
            placeholder = match.group(0).strip('{}')
            # Return the replacement for the placeholder if it exists
            return id.get(placeholder, match.group(0))

            # Regex to match anything in curly braces

        # Regex to match anything in curly braces, e.g. {videoid}, {postid}, etc.

        if id is None:
            return path
        if isinstance(id, int):
            id = str(id)

        return re.sub(r"\{[^}]+\}", id, path)

    def generate_authentication_prompts(self):
        """
            Generate a list of prompts for testing authentication mechanisms on protected endpoints.

            This function constructs test prompts for various authentication scenarios, including:
            - Accessing protected endpoints with different user accounts.
            - Using login credentials to acquire tokens.
            - Testing endpoints that require path parameters like user IDs.
            - Verifying refresh token mechanisms if applicable.

            Returns:
                list: A list of prompts for testing authentication and authorization.
            """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "GET")

        prompts = self.resource_endpoints(prompts)

        if len(endpoints) != 0:
            for endpoint, login in zip(endpoints, self.login_endpoint):
                for account in self.accounts:
                    endpoint_dict = endpoint
                    if isinstance(endpoint, dict):
                        endpoint = endpoint.get("path")

                    login_path, login_schema = self.get_path_and_schema(login)
                    if login_schema is None:
                        continue
                    login_schema = self.fill_in_schema_with_account(login_schema, account)

                    if "api" in endpoint and len(endpoint.split("/")) > 0 and "api" in account:
                        if account["api"] in endpoint:
                            prompts = self.test_authentication(endpoint, account, prompts)
                    else:
                        prompts = self.test_authentication(endpoint, account, prompts)
                    if "_id}" in endpoint:
                        endpoint = self.replace_id_placeholder(endpoint, "1")

                    if login_path:

                        if "api" in endpoint and len(endpoint.split("/")) > 0:
                            if account["api"] in endpoint:
                                id = account.get("id")
                                if id and "{id}" in endpoint:
                                    new_endpoint = endpoint.replace("{id}", str(account.get("id")))
                                    prompts = self.test_token(login_path, new_endpoint, account, login_schema, prompts)
                                    prompts = self.random_common_users(new_endpoint, login_path, login_schema, prompts)
                                else:

                                    prompts = self.test_token(login_path, endpoint, account, login_schema, prompts)
                                    prompts = self.random_common_users(endpoint, login_path, login_schema, prompts)

                        else:
                            if "id}" in endpoint:
                                endpoint = self.replace_placeholders_with_1(endpoint, f"{account.get('id')}")
                                prompts = self.random_common_users(endpoint, login_path, login_schema, prompts)
                                prompts = self.test_token(login_path, endpoint, account, login_schema, prompts)

            if self.current_refresh_endpoint:
                refresh_get_endpoints = self.get_correct_endpoints_for_method("refresh_endpoint", "GET")
                refresh_post_endpoints = self.get_correct_endpoints_for_method("refresh_endpoint", "POST")
                if len(refresh_get_endpoints) != 0 and refresh_post_endpoints:
                    for account in self.accounts:

                        for refresh_get_endpoint, refresh_post_endpoint in zip(refresh_get_endpoints,
                                                                               refresh_post_endpoints):
                            if "id}" in refresh_get_endpoint:
                                refresh_get_endpoint = self.replace_placeholders_with_1(refresh_get_endpoint,
                                                                                        account.get("id"))
                                if account["api"] in refresh_get_endpoint:
                                    prompts = self.test_refresh_token(refresh_post_endpoint, refresh_get_endpoint,
                                                                      account, prompts)
                                else:
                                    prompts = self.test_refresh_token(refresh_post_endpoint, refresh_get_endpoint,
                                                                      account, prompts)

        return prompts

    def generate_authorization_prompts(self):
        """
        Generate prompts to test authorization and role-based access control (RBAC)
        on protected endpoints.

        This method performs a series of authorization tests by:
        - Generating prompts for GET requests to protected endpoints.
        - Including user-specific endpoints like "users".
        - Excluding endpoints related to "community".
        - Testing RBAC behavior across different roles (admin, user, guest).
        - Verifying proper handling of user-specific data and ID placeholders.
        - Checking for data masking mechanisms.
        - Running CRUD operation tests on relevant endpoints.

        Returns:
            list: A list of authorization prompts for validating access control.
        """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "GET")

        users_ep = [ep + "s" for ep in self.endpoints if ep.endswith("user")]
        endpoints = endpoints + users_ep
        endpoints = [ep for ep in endpoints if "community" not in ep]
        if len(endpoints) != 0:
            for endpoint in endpoints:
                for account in self.accounts:
                    if isinstance(endpoint, dict):
                        endpoint = endpoint.get("path")
                        if "api" in endpoint and len(
                                endpoint.split("/")) > 0 and "id" in endpoint and not "identity" in endpoint:

                            if "api" in account and account["api"] in endpoint:

                                prompts = self.resource_prompts(endpoint, account, prompts)

                                prompts = self.mechanic_report(endpoint, account, prompts)
                                if "{id}" in endpoint:
                                    id = account.get("id")
                                    prompts = self.rbac(endpoint, account, prompts, id=id)
                                else:

                                    prompts = self.rbac(endpoint, account, prompts)

                                # Verify Data Masking
                                prompts = self.verify_data_masking(endpoint, account, prompts)


                        else:

                            prompts = self.resource_prompts(endpoint, account, prompts)

                            prompts = self.mechanic_report(endpoint, account, prompts)
                            if "_id}" in endpoint:
                                if "id" in account:
                                    id = account.get("id")
                                else:
                                    id = 1
                                endpoint = self.replace_id_placeholder(endpoint, str(id))

                            if self.admin and self.guest:
                                prompts.append(

                                    # Verify Role-Based Access Control (RBAC)

                                    {
                                        "objective": "Verify Role-Based Access Control (RBAC)",
                                        "steps": [
                                            f"send a GET request to {endpoint} with an 'admin' role authentication token in the Authorization header. Expect a 200 OK response, indicating access to all resources. Verify that the response data includes complete access to the endpoint, reflecting the admin’s permissions.user:{account}.\n",
                                            f"send a GET request to {endpoint} with a 'user' role authentication token in the Authorization header. Expect a 200 OK response, but confirm that only authorized resources or data for a regular user are included in the response. Verify that any restricted admin-only resources are not accessible to the user role.user:{account}.\n",
                                            f"send a GET request to {endpoint} with a 'guest' role authentication token (or without an authentication token if guests are unauthenticated). Expect either a 403 Forbidden or a 404 Not Found response if guests are not permitted to access the endpoint, or a 200 OK with limited data if some resources are publicly accessible to guests.user:{account}.\n"
                                        ],
                                        "path": [endpoint, endpoint, endpoint],
                                        "expected_response_code": [
                                            "200 OK for admin, confirming full access.",
                                            "200 OK for users, confirming access is limited to non-admin resources.",
                                            "403 Forbidden or 404 Not Found for guests if no access is granted, or 200 OK if limited access is applicable."
                                        ],
                                        "token": [self.admin.get("token"), account.get("token"),
                                                  self.guest.get("token")],
                                        "security": [
                                            "Verify that the response data includes complete access to the endpoint, reflecting the admin’s permissions.",
                                            "Verify that any restricted admin-only resources are not accessible to the user role.",
                                            "Verify that guest role has no or limited access."],

                                    }

                                    # This prompt tests the RBAC implementation by confirming that each user role has the appropriate access level:
                                    # - Admin has full access
                                    # - User has restricted access
                                    # - Guest has no or limited access.

                                )

                            else:
                                prompts = self.rbac(endpoint, account, prompts)

                            # Verify Data Masking
                            prompts = self.verify_data_masking(endpoint, account, prompts)

            prompts = self.test_crud(endpoints, prompts)
        return prompts

    def key_in_path(self, path, dictionary):
        # Split the path into components
        path_parts = path.split('/')

        # Check each part of the path to see if it is a key in the dictionary
        for part in path_parts:
            part = part.replace("{", "")
            part = part.replace("}", "")

            if part in dictionary:
                return True, part  # Return True and the matching part if found

        return False, None  # Return False and None if no part matches

    def generate_special_authentication(self):
        """
        Generate prompts for advanced authentication testing.

        This method focuses on testing the security robustness of login and authentication mechanisms.
        It includes:
        - Injection tests with special accounts (e.g., "bender" accounts).
        - Brute force protection validation using repeated login attempts.
        - CSS (Content Sniffing) vulnerability checks on authentication endpoints.
        - Token revocation checks after login.
        - ID substitution for user-specific paths.
        - Custom test cases for comments and advanced login workflows.

        Returns:
            list: A list of prompts targeting special authentication test cases.
        """
        prompts = []

        self.counter = self.counter + 1

        for login in self.login_endpoint:

            login_path, login_schema = self.get_path_and_schema(login)

            prompts = self.test_injection_bender_account(login_path, prompts)

            if login_path:
                prompts = self.test_brute_force(login_path, login_schema, prompts)

            for acc in self.accounts:

                if "api" in login_path and "api" in acc.keys():
                    if acc["api"] in login_path:
                        str_id = f"{acc.get('id')}"
                        login_path = login_path.replace("{id}", str_id)

                        str = [
                                  f"Attempt Login with Invalid Credentials - Send repeated POST requests to the login endpoint {login_path} using invalid credentials (e.g., incorrect password) {self.get_credentials(login_schema, login_path)}. " +
                                  f"Simulate a high rate of attempts (e.g., 10 requests within 1 minute) to trigger potential brute force protection mechanisms. "] * 10

                        if login_path:
                            prompts.append(  # Brute Force Protection
                                {
                                    "objective": "Brute Force Protection",
                                    "steps": str,
                                    "expected_response_code":
                                        [[
                                            "429 Too Many Requests to indicate effective rate-limiting measures against brute force attacks.",
                                            "403 Forbidden as an alternative response indicating account lockout or other security measures preventing further attempts."
                                        ]] * 10,
                                    "token": [""] * 10,
                                    "path": [login_path] * 10,
                                    "security":
                                        ["Ensure that user cannot login with invalid credentials.\n" +
                                         "Ensure that rate-limiting mechanisms are robust and properly configured to prevent brute force attacks by limiting the number of allowed failed attempts within a given time frame. This prevents attackers from trying a large number of combinations in a short period.\n" +
                                         "Check that account lockout mechanisms or other access denial policies are effective in disabling further login attempts after a certain number of failures, protecting against continuous brute force attempts and securing user accounts from unauthorized access."]

                                }
                            )
                        if self.auth_endpoint:
                            if acc["api"] in login_path:
                                str_id = f"{acc.get('id')}"
                                login_path = login_path.replace("{id}", str_id)

                            get_paths = self.get_correct_endpoints_for_method("auth_endpoint", "GET")
                            post_paths = self.get_correct_endpoints_for_method("auth_endpoint", "POST")

                            for get_path in get_paths:
                                if acc["api"] in get_path:
                                    str_id = f"{acc.get('id')}"
                                    get_path = get_path.replace("{id}", str_id)
                                    prompts = self.test_css(get_path, prompts)

                            for post_path in post_paths:
                                if acc["api"] in post_path:
                                    str_id = f"{acc.get('id')}"
                                    post_path = post_path.replace("{id}", str_id)
                                    schema = self.openapi_spec_parser.get_schema_for_endpoint(post_path, "POST")
                                    prompts = self.test_css(post_path, prompts, schema=schema)

                            if self.current_protected_endpoint:
                                get_endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "GET")

                                for get_endpoint in get_endpoints:
                                    for account in self.accounts:
                                        if acc["api"] in get_endpoint:
                                            str_id = f"{acc.get('id')}"
                                            get_endpoint = get_endpoint.replace("{id}", str_id)
                                        prompts = self.test_token(login_path, get_endpoint, account, login_schema,
                                                                  prompts, revocation=True)


                else:

                    if login_path:
                        prompts = self.test_brute_force(login_path, login_schema, prompts, number=10)

                        if self.auth_endpoint:

                            get_paths = self.get_correct_endpoints_for_method("auth_endpoint", "GET")
                            post_paths = self.get_correct_endpoints_for_method("auth_endpoint", "POST")

                            for get_path in get_paths:
                                prompts = self.test_css(get_path, prompts)

                            for post_path in post_paths:
                                schema = self.openapi_spec_parser.get_schema_for_endpoint(post_path, "POST")
                                prompts = self.test_css(post_path, prompts, schema=schema)

                        if self.current_protected_endpoint:
                            get_endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "GET")

                            for get_endpoint in get_endpoints:
                                for account in self.accounts:
                                    if "id}" in get_endpoint:
                                        get_endpoint = self.replace_placeholders_with_1(get_endpoint, account.get("id"))

                                    prompts = self.test_token(login_path, get_endpoint, account, login_schema, prompts,
                                                              revocation=True)

                    # return prompts

                prompts = self.test_comment(acc, prompts)


                return prompts

        return prompts

    def generate_input_validation_prompts(self):
        """
           Generate prompts for testing input validation vulnerabilities on POST endpoints.

           This method targets both protected and public POST endpoints and performs:
           - SQL Injection testing using the account context and endpoint schema.
           - General input validation testing (e.g., missing fields, invalid types).

           For each endpoint and account combination, the method replaces path parameters (like {id})
           and checks the relevant OpenAPI schema to craft test cases.

           Returns:
               list: A list of prompts designed to evaluate input validation robustness.
           """
        prompts = []

        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "public_endpoint", "POST")
        if self.current_protected_endpoint:

            for ep in endpoints:
                for account in self.accounts:
                    post_endpoint = ep.get("path")
                    schema = self.openapi_spec_parser.get_schema_for_endpoint(post_endpoint, "POST")
                    if "api" in account.keys() and account["api"] in ep:
                        str_id = f"{account.get('id')}"
                        post_endpoint = ep.replace("{id}", str_id)

                        prompts = self.test_sql_injection(account, post_endpoint, schema, prompts)

                        prompts = self.test_inputs(post_endpoint, schema, account, prompts)



                    else:
                        prompts = self.test_sql_injection(account, post_endpoint, schema, prompts)

                        prompts = self.test_inputs(post_endpoint, schema, account, prompts)

        return prompts

    def generate_error_handling_prompts(self):
        """
          Generate prompts for testing error handling on POST endpoints.

          This method verifies that endpoints respond with meaningful and secure error messages
          when provided with incorrect or malformed input.

          It combines protected and public POST endpoints, retrieves their schemas, and uses
          account information to inject malformed or edge-case data to observe error behavior.

          Returns:
              list: A list of prompts to test the robustness and clarity of error handling.
          """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "public_endpoint", "POST")

        for ep in endpoints:
            post_endpoint = ep.get("path")
            schema = self.openapi_spec_parser.get_schema_for_endpoint(post_endpoint, "POST")
            for account in self.accounts:
                if "api" in post_endpoint and "api" in account.keys() and account["api"] in ep:
                    str_id = f"{account.get('id')}"
                    post_endpoint = ep.replace("{id}", str_id)

                    prompts = self.test_error_handling(post_endpoint, account, schema, prompts)


                else:
                    prompts = self.test_error_handling(post_endpoint, account, schema, prompts)

        return prompts

    def generate_session_management_prompts(self):
        """
           Generate prompts for testing session management and security.

           This method checks GET endpoints (both protected and public) for:
           - Proper session validation.
           - Session hijacking resistance.
           - Session-related cookie attributes (e.g., HttpOnly, Secure).
           - Other session vulnerabilities.

           It also evaluates login endpoints to simulate authentication flows and test
           how sessions are managed, maintained, and secured afterward.

           Returns:
               list: A list of prompts testing session integrity, hijacking protections, and cookie configurations.
           """
        prompts = []

        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "GET") + self.get_correct_endpoints_for_method(
            "public_endpoint", "GET")

        for get_endpoint, _, _ in endpoints:
            # Check if API Uses Session Management
            for account in self.accounts:
                if "api" in account and  account["api"] in get_endpoint:
                    str_id = f"{account.get('id')}"
                    get_endpoint = get_endpoint.replace("{id}", str_id)

                    prompts = self.test_session_management(get_endpoint, account, prompts)


                else:
                    if "id}" in get_endpoint:
                        get_endpoint = self.replace_placeholders_with_1(get_endpoint, account.get("id"))
                    prompts = self.test_session_management(get_endpoint, account, prompts)

                if self.login_endpoint:
                    for login in self.login_endpoint:

                        login_path, login_schema = self.get_path_and_schema(login)
                        if login_schema is None:
                            continue
                        if "api" in account and account["api"] in login_path:
                            str_id = f"{account.get('id')}"
                            login_path = login_path.replace("{id}", str_id)

                            prompts = self.test_session_hijacking(login_path, get_endpoint, login_schema, account,
                                                                  prompts)

                        else:
                            prompts = self.test_session_hijacking(login_path, get_endpoint, login_schema, account,
                                                                  prompts)
                        prompts = self.test_sessions_vulnerabilitiy(login_path, login_schema, account, prompts)

                        prompts = self.test_cookies(login_path, login_schema, prompts)

        return prompts

    def generate_xss_prompts(self):
        """
           Generate prompts for detecting Cross-Site Scripting (XSS) vulnerabilities.

           This method covers both POST and GET endpoints, targeting public and protected resources.
           It attempts to inject malicious XSS payloads into input fields (via POST) and query parameters (via GET),
           and then observes the responses for evidence of unescaped rendering or unsafe HTML reflection.

           Returns:
               list: A list of prompts designed to detect XSS vulnerabilities.
           """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "public_endpoint", "POST")

        for account in self.accounts:

            for post_endpoint, _, _ in endpoints:
                schema = self.openapi_spec_parser.get_schema_for_endpoint(post_endpoint, "POST")
                prompts = self.test_xss(post_endpoint, account, schema, prompts)

            endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                              "GET") + self.get_correct_endpoints_for_method(
                "public_endpoint", "GET")
            for get_endpoint, _, _ in endpoints:
                if "id}" in get_endpoint:
                    get_endpoint = self.replace_placeholders_with_1(get_endpoint, account.get("id"))

                    prompts = self.test_xss_query(get_endpoint, account, prompts)

        return prompts

    def generate_csrf_prompts(self):
        """
           Generate prompts to test Cross-Site Request Forgery (CSRF) protection.

           This method tests if sensitive endpoints are protected from unauthorized or forged requests
           by simulating actions like changing user data without a valid CSRF token.
           It also checks cookie configurations to ensure proper CSRF defense mechanisms are in place.

           Returns:
               list: A list of CSRF-related prompts covering POST and GET requests on sensitive endpoints.
           """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("sensitive_data_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "sensitive_data_endpoint", "POST")
        for account in self.accounts:
            for sensitive_action_endpoint in endpoints:
                schema = sensitive_action_endpoint.get("schema")
                prompts = self.test_csrf(sensitive_action_endpoint, schema, prompts, method="POST")
            endpoints = self.get_correct_endpoints_for_method("sensitive_data_endpoint",
                                                              "GET") + self.get_correct_endpoints_for_method(
                "sensitive_data_endpoint", "GET")
            for sensitive_data_endpoint in endpoints:
                if "id}" in sensitive_data_endpoint:
                    sensitive_data_endpoint = self.replace_placeholders_with_1(sensitive_data_endpoint,
                                                                               account.get("id"))
                    prompts = self.test_csrf(sensitive_data_endpoint, None, prompts, method="GET")

            # This prompt tests if the API applies CSRF protection to GET requests that handle sensitive data.

            for login in self.login_endpoint:

                login_path, login_schema = self.get_path_and_schema(login)
                if login_schema is None:
                    continue
                if login_path:
                    prompts = self.test_cookies(login_path, login_schema, prompts, account=account)

        return prompts

    def generate_business_logic_vul_prompts(self):
        """
           Generate prompts to test for business logic vulnerabilities.

           These include logic flaws like privilege escalation, incorrect role validation,
           or bypassing user controls. The method targets both protected and public POST endpoints,
           as well as sensitive GET endpoints and role-based POST operations.

           Returns:
               list: A list of prompts to test business rules and role validation logic.
           """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "public_endpoint", "POST")
        for account in self.accounts:

            for endpoint, _, _ in endpoints:
                schema = self.openapi_spec_parser.get_schema_for_endpoint(endpoint, "POST")
                prompts = self.test_buisness_logic(endpoint, schema, account, prompts, method="POST")

            get_endpoints = self.get_correct_endpoints_for_method("sensitive_data_endpoint", "GET")

            for endpoint, _, _ in get_endpoints:
                if "id}" in endpoint:
                    get_endpoint = self.replace_placeholders_with_1(endpoint, account.get("id"))
                prompts = self.test_buisness_logic(endpoint, None, account, prompts, method="GET")
            post_endpoints = self.get_correct_endpoints_for_method("role_access_endpoint", "POST")

            for post_endpoint, _, _ in post_endpoints:
                schema = self.openapi_spec_parser.get_schema_for_endpoint(post_endpoint, "POST")
                prompts = self.test_roles(post_endpoint, schema, account, prompts)

        return prompts

    def generate_rate_limit_throttling(self):
        """
        Generate prompts to test rate limiting and throttling protections.

        This method simulates high-frequency requests to login and OTP endpoints
        to detect absence of proper rate-limiting mechanisms, which could lead to
        brute-force attacks or denial-of-service (DoS).

        Returns:
            list: A list of prompts that test for request throttling, OTP abuse, and rate limits.
        """
        prompts = []
        for login in self.login_endpoint:

            login_path, login_schema = self.get_path_and_schema(login)
            request = [
                          f"Send a large number of POST requests to {login_path} based on schema {login_schema} within a short timeframe."] * 10
            if login_path:
                prompts = self.test_limiting(request, login_path, prompts)

        # OPT test cases
        opt_endpoints = [ep for ep in self.endpoints if "otp" in ep]

        for opt_endpoint in opt_endpoints:
            numbers = list(range(0000, 10000))

            # Pick 10 random numbers from the list
            random_numbers = random.sample(numbers, 10)
            random_numbers = [1872] + random_numbers
            for number in random_numbers:
                otp = {"otp": f"{number}"}

                prompts = prompts + [

                    {
                        "objective": "Test for Unrestricted Resource Consumption",
                        "steps": [
                            f"Send a  POST request to trigger the sending of an OTP to a mobile phone number. This is intended to test the system's resilience against DoS attacks through resource exhaustion. Request should look like the following:{otp}"
                        ],
                        "token": [""],
                        # Assuming no authentication is required for this endpoint, or specify where needed
                        "path": [opt_endpoint],  # Specify the actual endpoint for sending OTP
                        "expected_response_code": [
                            "403 Forbidden"
                        ],
                        "security": [
                            "Verify that msg is not '4 Digit OPT sent on mobile no.'",

                        ]
                    }
                    ,
                    {
                        "objective": "Testing for Unrestricted Resource Consumption",
                        "steps": [
                            f"Send a  POST requests to trigger the verify an OTP to a mobile phone number. Request should look like the following:{otp}"
                        ],
                        "token": [""],
                        # Assuming no authentication is required for this endpoint, or specify where needed
                        "path": [opt_endpoint],  # Specify the actual endpoint for sending OTP
                        "expected_response_code": [
                            "403 Forbidden"
                        ],
                        "security": [
                            "Verify that request is okay",

                        ]
                    }
                ]

        prompts = self.test_throttling(prompts)
        return prompts

    def generate_security_misconfiguration_prompts(self):
        """
          Generate prompts for identifying security misconfigurations in the API.

          This method checks for:
          - Missing or misconfigured security-related HTTP headers (e.g., CSP, X-Frame-Options).
          - Insecure key exposure through endpoint patterns.
          - Incorrect CORS settings that may lead to data leakage.
          - Disclosure of sensitive debug or configuration information in error responses.

          Returns:
              list: A list of prompts targeting potential security misconfiguration vulnerabilities.
          """
        prompts = []

        user_endpoints = [ep for ep in self.endpoints if ep.endswith("user")]

        for key_endpoint in user_endpoints:
            for account in self.accounts:
                if account["api"] in key_endpoint:
                    if "key" in account:
                        prompts = self.test_limiting("", key_endpoint, prompts, account.get("key"))

        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "GET") + self.get_correct_endpoints_for_method(
            "public_endpoint", "GET")
        user_endpoints = [ep for ep in self.endpoints if "key" in ep]
        endpoints = endpoints + user_endpoints

        for endpoint in endpoints:
            if isinstance(endpoint, dict):
                endpoint = endpoint.get("path")
            for account in self.accounts:
                id = account.get("id")
                if f"{id}".isdigit() and "{id}" in endpoint:
                    endpoint = endpoint.replace("{id}", f"{id}")
                prompts.append(

                    # Check for Security Misconfigurations in Headers
                    {
                        "objective": "Check for Security Misconfigurations in Headers",
                        "steps": [
                            f"Send a GET request to {endpoint}.",

                        ],
                        "path": [endpoint],
                        "token": [account.get("token")],
                        "expected_response_code": [
                            "200 OK with response headers correctly set to include security-related configurations such as X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, and Content-Security-Policy."
                        ],
                        "security": [
                            "Inspect the response headers, including X-Content-Type-Options, X-Frame-Options, and Content-Security-Policy.",
                            "Verify if these headers are properly configured to mitigate security risks."
                            "Ensure that response headers are configured to prevent security vulnerabilities such as clickjacking, MIME type sniffing, and XSS.",
                            "Verify that no unnecessary or insecure headers are present in the response."
                            "Check if 'Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true' is set as these headers indicate that the CORS policy for the given request is misconfigured, allowing it to be invoked from a third-party web application to access the resource and obtain sensitive information like the user's ID, username, password, and auth key."
                        ]
                    }

                    # This prompt tests if security headers are properly configured to prevent exposure to security risks.
                )
        endpoints = self.get_correct_endpoints_for_method("secure_action_endpoint",
                                                          "POST")
        for endpoint in endpoints:
            for account in self.accounts:
                id = account.get("id")
                endpoint = endpoint.replace("{id}", f"{id}")

                schema = self.openapi_spec_parser.get_schema_for_endpoint(endpoint, "POST")
                for account in self.accounts:
                    prompts.append(
                        # Inspect API for Debug or Error Information Exposure
                        {
                            "objective": "Inspect API for Debug or Error Information Exposure",
                            "steps": [
                                f"Send an invalid POST request to {endpoint} based on schema {schema}.",

                            ],
                            "token": [account.get("token")],
                            "path": [endpoint],
                            "expected_response_code": [
                                "400 Bad Request or 403 Forbidden with a generic error message that does not disclose sensitive internal details."
                            ],
                            "security": [
                                "Check if the response contains detailed error messages or debug information.",
                                "Verify that the response provides only minimal and generic error messages."
                                "Ensure that the API avoids exposing debug or configuration details in error responses.",
                                "Verify that sensitive system information is not included in error messages."
                            ]
                        }

                        # This prompt tests if the API avoids exposing sensitive configuration or debug information.
                    )

        return prompts

    def generate_logging_monitoring_prompts(self):
        """
          Generate prompts to test whether the API performs proper logging and monitoring.

          This method simulates:
          - Invalid request submissions to see if they are logged appropriately.
          - Potentially malicious requests (e.g., SQL injection attempts).
          - Logging of unexpected or unauthorized access attempts.

          It ensures that logs are meaningful, timely, and privacy-compliant without exposing sensitive data.

          Returns:
              list: A list of prompts to verify proper logging and monitoring mechanisms.
          """
        prompts = []
        endpoints = self.get_correct_endpoints_for_method("secure_action_endpoint",
                                                          "POST")
        flag_endpoints = [ep for ep in self.endpoints if "flag" in ep]
        endpoints = flag_endpoints + endpoints

        for endpoint in endpoints:
            if isinstance(endpoint, dict):
                endpoint = endpoint.get("path")
            schema = self.openapi_spec_parser.get_schema_for_endpoint(endpoint, "POST")
            for account in self.accounts:
                prompts.append(
                    # Test Logging for Incorrect Requests
                    {
                        "objective": "Test Logging for Incorrect Requests",
                        "steps": [
                            f"Send an invalid POST request to {endpoint} based on schema {schema}.",
                        ],
                        "path": [endpoint],
                        "token": [account.get("token")],
                        "expected_response_code": [
                            "400 Bad Request or 403 Forbidden, with the API logging details of the failed attempt."
                        ],
                        "security": [
                            "Verify if the API logs the details of the failed request, including timestamp, user information, and the nature of the error."
                            "Ensure that the API logs invalid requests comprehensively to assist in debugging and identifying potential misuse.",
                            "Verify that logs do not include sensitive user data or details beyond what is necessary for monitoring."
                        ]
                    }

                    # This prompt tests if the API logs incorrect requests, including any errors encountered.
                )
        endpoints = self.get_correct_endpoints_for_method("secure_data_endpoint",
                                                          "GET")
        params = [{"username": "' OR 1=1 #", "password": "password"}, {"username": "'", "password": "password"},
                  {"username": "admin", "password": "'"}]

        for endpoint in endpoints:
            if isinstance(endpoint, dict):
                endpoint = endpoint.get("path")

            for account in self.accounts:
                if "id}" in endpoint:
                    endpoint = self.replace_placeholders_with_1(endpoint, account.get("id"))
                    for paramerts in params:
                        prompts.append(
                            # Test Logging for Potentially Malicious Requests
                            {
                                "objective": "Test Logging for Potentially Malicious Requests",
                                "steps": [
                                    f"Send a GET request to {endpoint} with unusual or malicious parameters, such as SQL injection attempts. Request body should look like this: {paramerts}",
                                ],
                                "token": [account.get("token")],
                                "path": [endpoint],
                                "expected_response_code": [
                                    "200 OK",
                                    "400 Bad Request with the API logging the details of the suspicious request, including the malicious parameters and IP address."
                                ],
                                "security": [
                                    "Check if the API logs the suspicious request and flags it for further analysis or monitoring."
                                    "Ensure that the API logs potentially malicious requests and flags them for review to mitigate security threats.",
                                    "Verify that logs are monitored for patterns of abuse or repeated attacks."
                                ]
                            }

                            # This prompt tests if the API logs and monitors potentially malicious requests to help detect and respond to security threats.
                        )
        return prompts

    def get_correct_endpoints_for_method(self, type_of_endpoint, method):
        endpoints = []
        for type_ep in self.categorized_endpoints.keys():
            if type_of_endpoint == type_ep:
                x = self.categorized_endpoints[type_of_endpoint]
                if x is not None:
                    for entry in x:  # Assuming x is a list of dictionaries
                        if entry.get('method') == method:
                            endpoints.append(entry)
        return endpoints

    def generate_random_numbers(self, length=10):

        number = ''.join(str(random.randint(0, 9)) for _ in range(length))
        while number in self.available_numbers:
            number = ''.join(str(random.randint(0, 9)) for _ in range(length))

        self.available_numbers.append(number)
        return number

    def get_credentials(self, schema, endpoint, new_user=False):
        """
            Fill username and password fields in the provided schema.

            Args:
                schema (dict): A schema dictionary containing an example.
                username (str): The username to populate in the example.
                password (str): The password to populate in the example.

            Returns:
                dict: Updated schema with username and password fields filled.
            """
        # Deep copy the schema to avoid modifying the original
        updated_schema = copy.deepcopy(schema)
        example = None

        if schema is not None:
            if "example" in updated_schema.keys():
                updated_schema["example"] = self.fill_schema(updated_schema["example"])
            else:
                updated_schema = self.adjust_schema_with_examples(updated_schema)

            if "example" in updated_schema:
                example = updated_schema["example"]
            if endpoint not in self.credentials.keys() or new_user:

                # Check if 'example' exists and is a dictionary
                if updated_schema is not None and "example" in updated_schema.keys():
                    example = updated_schema.get("example")

                if example is None:
                    example = {}
                    if "email" not in example or example["email"].startswith("{{"):
                        example['email'] = self.faker.email()
                    if "name" not in example or example["name"].startswith("{{"):
                        example["name"] = self.faker.name()
                    if "number" not in example:
                        if schema is not None and "properties" in schema.keys():
                            example["number"] = int(self.generate_random_numbers())
                        else:
                            example["number"] = 1
                    if "username" in example and example["username"].startswith("{{"):
                        example["username"] = self.faker.user_name()
                else:
                    if "email" in example and "{{" in example["email"]:
                        example["email"] = self.faker.email()
                    if "password" in example and "{{" in example["password"]:
                        password = self.faker.password(special_chars=False)
                        if "passwordRepeat" in example  and "{{" in example["passwordRepeat"]:
                            example["passwordRepeat"] = password
                        example["password"] = password
                    if "number" in example:
                        if "{{" in example["number"] or "phone" in example["number"]:
                            example["number"] = int(self.generate_random_numbers())
                    if "username" in example:
                        example["username"] = self.faker.user_name()

                if updated_schema is None:
                    updated_schema = {}
                updated_schema["example"] = example
                self.credentials[endpoint] = updated_schema

            else:
                updated_schema = self.credentials[endpoint]

        return updated_schema

    def fill_schema(self, schema, params=None):
        if params:
            field_to_faker = params
        else:

            field_to_faker = {
                'name': self.faker.name,
                'email': self.faker.email,
                'phone': self.faker.phone_number,
                'password': self.faker.password,
                'address': self.faker.address,
                'city': self.faker.city,
                'username': self.faker.user_name,
                "old_email": "adam007@example.com",
                "new_email": self.faker.email,
                "price": -2000,
                "number_of_repeats": 10000,
            }
        filled_schema = {}
        if schema:
            for key, value in schema.items():
                # Attempt to find a Faker provider for the key

                provider = field_to_faker.get(key)
                if provider:
                    # If a provider is found, use it to generate fake data
                    if key == "password":
                        filled_schema[key] = self.faker.password(special_chars=False)
                    else:
                        if not callable(provider):
                            filled_schema[key] = self.faker.random_letters()
                        else:
                            filled_schema[key] = provider()
                else:
                    # If no provider is found, revert to a default or keep the original value
                    filled_schema[key] = value
        return filled_schema

    def set_login_schema(self, account, login_schema):
        if "username" in login_schema.keys():
            if "username" in account.keys():
                login_schema["username"] = account["username"]
            elif "email" in account.keys():
                login_schema["username"] = account["email"]

        if "password" in login_schema.keys():
            login_schema["password"] = account["password"]

        return login_schema

    def adjust_schema_with_examples(self, schema: dict) -> dict:
        """
        Move 'example' values from each property into a separate 'example' dict.
        """
        new_schema = schema.copy()
        example_dict = {}

        if 'properties' in schema:
            for field, field_props in schema['properties'].items():
                if 'example' in field_props:
                    example_dict[field] = field_props.pop('example')
                if "properties" in field_props:
                    if field not in example_dict or not isinstance(example_dict[field], dict):
                        example_dict[field] = {}

                    for field1, field_props1 in field_props['properties'].items():
                        if 'example' in field_props1:
                            example_dict[field][field1] = field_props1.pop('example')


            # Add collected examples
            if example_dict:
                new_schema['example'] = example_dict

        return new_schema

    def create_random_bearer_token(self, length=16):
        """
        Generates a random token using hex encoding and prefixes it with "Bearer ".
        :param length: Number of bytes for the random token (each byte becomes two hex characters).
        :return: A string in the format "Bearer <random-hex>".
        """
        token_value = secrets.token_hex(length)
        return f"{token_value}"

    def get_invalid_credentials(self, account):
        invalid_account = {}
        for values, keys in account.items():
            if isinstance(values, str):
                invalid_account[keys] = values + "1"
            elif values.isnumeric():
                invalid_account[keys] = values + 1
            else:
                invalid_account[keys] = "_" + values
        return invalid_account

    def create_account(self, login_schema, login_path):
        account = self.get_credentials(login_schema, login_path, new_user=True)
        if account is None:
            return None
        if "example" in account:
            account = account.get("example")
        account["x"] = self.counter
        parts = [api for api in login_path.split("/") if api.strip()]
        api = [part for part in parts if part.startswith("api")]
        if len(api) > 0:
            api = api[0]
            account["api"] = api
        return account

    def assign_brute_force_endpoints(self, admin):
        file = self.config.get("password_file")
        if file == "Not found":
            return
        else:
            password_list_path = self.get_file(file)[0]

        # Open the password list file
        with open(password_list_path, "r") as file:
            passwords = file.readlines()

        # Strip any extra whitespace characters (newlines, spaces)
        passwords = [password.strip() for password in passwords]

        # Start brute-force attack
        for password in passwords:
            # Create the data for the POST request
            data = {
                'username': admin,
                'password': password
            }
            self.brute_force_accounts.append(data)

    def get_comment_ep(self):
        for ep in self.endpoints:
            if "comment" in ep:
                return ep

    def fill_in_schema_with_account(self, login_schema, account):
        if login_schema is not None:
            if "token" in login_schema and "token" in account:
                login_schema["token"] = account["token"]
            if "email" in login_schema and "email" in account:
                login_schema["email"] = account["email"]
            if "password" in login_schema and "password" in account:
                login_schema["password"] = account["password"]
            if "username" in login_schema and "username" in account:
                login_schema["username"] = account["username"]
        return login_schema

    def mechanic_report(self, endpoint, account, prompts):
        if "mechanic_report" in endpoint:
            users = list(range(1, 100))
            random_numbers = random.sample(users, 10)
            random_numbers = [5] + random_numbers

            for i in random_numbers:
                new_endpoint = endpoint + f"?report_id={i}"
                prompts.append(

                    # Access Control to Specific Resources
                    {
                        "objective": "Access Control to Specific Resource of other used",
                        "steps": [
                            f"Attempting Access with Non-Owner's Credentials - Send a GET request to {new_endpoint} using an authentication token for User B (a different user who does not own the resource). user:{account}.\n",
                        ],
                        "path": [new_endpoint],
                        "expected_response_code": [
                            "403 Forbidden or 404 Not Found when accessed by a non-owner, confirming that access is appropriately restricted.",

                        ],
                        "token": [account.get("token")],
                        "security": [
                            "Ensure robust validation of user credentials and proper enforcement of access controls. Verify that the system correctly identifies ownership and prevents unauthorized access based on user authentication and authorization levels."
                            ]
                    }

                    # This prompt tests access control for resources that are user-owned by verifying:
                    # - Only the resource owner can access the data (User A)
                    # - Non-owners receive a restricted response (User B)
                    # - Unauthenticated requests are denied access (if applicable)
                )
        return prompts

    def random_common_users(self, endpoint, login_path, login_schema, prompts):

        random_entries = self.df.sample(n=10,
                                        random_state=42)  # Adjust random_state for different samples

        for index, random_entry in random_entries.iterrows():
            username = random_entry['username']
            password = random_entry['password']
            # Now you can print or use username and password as needed
            common_account = {"email": username, "password": password}
            prompts = prompts + [{
                "objective": "Attempt login with common username and password",
                "steps": [
                    f"Attempt to send a POST request to the login endpoint {login_path} using common login credentials {login_schema} with user:{common_account}.\n", ],
                "path": [login_path],
                "expected_response_code": [
                    "401 Unauthorized when attempting to authenticate with invalid credentials.",
                ],
                "token": [""],
                "security": [
                    "Ensure that the system rejects invalid credentials with a 401 Unauthorized status.",
                    "Ensure no sensitive information is leaked in the error responses, such as specific reasons for the failure."
                ]
            }]
        username = "savanna48@ortiz.com"
        password = "zTyBwV/9"
        common_account = {"email": username, "password": password}
        prompts = prompts + [{
            "objective": "Attempt login with common username and password",
            "steps": [
                f"Attempt to send a POST request to the login endpoint {login_path} using common login credentials {login_schema} with user:{common_account}.\n",
            ],
            "path": [login_path],
            "expected_response_code": [
                "401 Unauthorized when attempting to authenticate with invalid credentials.",
            ],
            "token": [""],
            "security": [
                "Ensure that the system rejects invalid credentials with a 401 Unauthorized status.",
                "Ensure no sensitive information is leaked in the error responses, such as specific reasons for the failure."
            ]
        }]

        return prompts

    def resource_prompts(self, endpoint, account, prompts):
        key_found, key = self.key_in_path(endpoint, self.resources)
        if key_found:
            for resource in self.resources[key]:
                new_endpoint = endpoint.replace("{", "").replace("}", "").replace(key, resource)

                prompts.append(

                    # Access Control to Specific Resources
                    {
                        "objective": "Access Control to Specific Resources",
                        "steps": [
                            f"Accessing Resource with Owner's Credentials - Send a GET request to {endpoint} using an authentication token for User A (a different user who does not own the resource). user:{account}.\n",
                            f"Attempting Access with Non-Owner's Credentials - Send a GET request to {endpoint} using an authentication token for User B (a different user who does not own the resource). user:{account}.\n",
                            f"Attempting Access without Authentication (if applicable) - Send a GET request to {endpoint} without any authentication token. Expect a 401 Unauthorized response, confirming that unauthenticated access is restricted."
                        ],
                        "path": [new_endpoint, new_endpoint, new_endpoint],
                        "expected_response_code": [
                            "403 Forbidden or 404 Not Found when accessed by a non-owner, confirming that access is appropriately restricted.",
                            "403 Forbidden or 404 Not Found when accessed by a non-owner, confirming that access is appropriately restricted.",
                            "401 Unauthorized for unauthenticated requests, ensuring that authentication is required for access."
                        ],
                        "token": [account.get("token"), self.create_random_bearer_token(), ""],
                        "security": [
                            "Ensure robust validation of user credentials and proper enforcement of access controls. Verify that the system correctly identifies ownership and prevents unauthorized access based on user authentication and authorization levels."
                            ]}

                    # This prompt tests access control for resources that are user-owned by verifying:
                    # - Only the resource owner can access the data (User A)
                    # - Non-owners receive a restricted response (User B)
                    # - Unauthenticated requests are denied access (if applicable)
                )
        return prompts

    def resource_endpoints(self, prompts):
        resource_endpoints = []
        for ep in self.endpoints:
            if "_id" not in ep and ("posts" and "recent" in ep or "mechanic" and "workshop" in ep or "dashboard" in ep):
                resource_endpoints.append(ep)

        resource_endpoints = list(set(resource_endpoints))

        for resource_endpoint in resource_endpoints:
            for account in self.accounts:
                token = account.get("token")
                prompts = prompts + [
                    {
                        "objective": "Get other data",
                        "steps": [
                            f"Send a GET request to the {resource_endpoint} with the token {token}.\n"
                        ],
                        "path": [resource_endpoint],
                        "token": [account.get("token")],
                        "expected_response_code": ["200 OK", "201 Created"],
                        "security": [
                            "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]
                    }

                ]
        return prompts

    def rbac(self, old_endpoint, account, prompts, id=None):
        endpoint = copy.deepcopy(old_endpoint)

        ids = [35] + list(range(1, 10))
        if id:
            ids = [id] + ids

        endpoint_and_new_endpoint = []
        for i in ids:
            token = "" if "login" not in endpoint else account.get("token")
            endpoint, endpoint_of_other_user = self.replace_ids(account, endpoint, given_id=i)
            if (endpoint, endpoint_of_other_user) in endpoint_and_new_endpoint:
                continue
            endpoint_and_new_endpoint.append((endpoint, endpoint_of_other_user))

            prompts = prompts + [

                # Verify Role-Based Access Control (RBAC)

                {
                    "objective": "Verify Role-Based Access Control (RBAC)",
                    "steps": [
                        # f"send a GET request to {endpoint} with an 'admin' role authentication token in the Authorization header. Expect a 200 OK response, indicating access to all resources. Verify that the response data includes complete access to the endpoint, reflecting the admin’s permissions.",
                        f"send a GET request to {endpoint} with a 'user' role authentication token in the Authorization header. Expect a 200 OK response, but confirm that only authorized resources or data for a regular user are included in the response. Verify that any restricted admin-only resources are not accessible to the user role. user:{account}.\n",
                        # f"send a GET request to {endpoint} with a 'guest' role authentication token (or without an authentication token if guests are unauthenticated). Expect either a 403 Forbidden or a 404 Not Found response if guests are not permitted to access the endpoint, or a 200 OK with limited data if some resources are publicly accessible to guests."
                    ],
                    "path": [endpoint, ],
                    "expected_response_code": [
                        # "200 OK for admin, confirming full access.",
                        "200 OK for users, confirming access is limited to non-admin resources.",
                        # "403 Forbidden or 404 Not Found for guests if no access is granted, or 200 OK if limited access is applicable."
                    ],
                    "token": [  # self.admin.get("token"),
                        token,
                        # self.guest.get("token")
                    ],
                    "security": [
                        "Verify that the response data includes complete access to the endpoint, reflecting the admin’s permissions.",
                        "Verify that any restricted admin-only resources are not accessible to the user role.",
                        "Verify that guest role has no or limited access."],

                },
                # Access Control to Specific Resources
                {
                    "objective": "Access Control to Specific Resources",
                    "steps": [
                        f"Accessing Resource with Owner's Credentials - Send a GET request to {endpoint} using an authentication token for User A (the owner of the resource). Expect a 200 OK response, confirming that User A can access their own data. Verify that the response includes the resource data as expected.user:{account}.\n",
                        f"Attempting Access with Non-Owner's Credentials - Send a GET request to {endpoint_of_other_user} using an authentication token for User B (a different user who does not own the resource). Expect a 403 Forbidden or 404 Not Found response, indicating that access is denied to resources not owned by the authenticated user.user:{account}.\n",
                        f"Attempting Access without Authentication (if applicable) - Send a GET request to {endpoint} without any authentication token. Expect a 401 Unauthorized response, confirming that unauthenticated access is restricted.user:{account}.\n"
                    ],
                    "path": [endpoint, endpoint_of_other_user, endpoint],
                    "expected_response_code": [
                        "200 OK when accessed by the owner, confirming correct owner access.",
                        "403 Forbidden or 404 Not Found when accessed by a non-owner, confirming that access is appropriately restricted.",
                        "401 Unauthorized for unauthenticated requests, ensuring that authentication is required for access."
                    ],
                    "token": [account.get("token"), self.create_random_bearer_token(), ""],
                    "security": [
                        "Ensure robust validation of user credentials and proper enforcement of access controls. Verify that the system correctly identifies ownership and prevents unauthorized access based on user authentication and authorization levels."
                        ]
                }

                # This prompt tests the RBAC implementation by confirming that each user role has the appropriate access level:
                # - Admin has full access
                # - User has restricted access
                # - Guest has no or limited access.
            ]

            endpoint = old_endpoint

        return prompts

    def verify_data_masking(self, endpoint, account, prompts):
        prompts = prompts + [

            {
                "objective": "Verify Data Masking",
                "steps": [
                    f"Restricted Access Verification - Send a GET request to {endpoint} with a user who has restricted access, verifying that only permissible fields are included in the response.user:{account}.\n",
                ],
                "expected_response_code": [
                    "200 OK for responses that correctly implement data masking, ensuring that data visibility is restricted according to user permissions."
                ],
                "path": [endpoint],
                "token": [account.get("token")],
                "security": [
                    " Confirm that sensitive data is either masked or excluded, ensuring that only authorized fields are visible to the user. Ensure that the system effectively masks or excludes sensitive data for users with restricted access. Verify that data masking is applied correctly and consistently across all applicable endpoints to maintain confidentiality and compliance with data protection regulations."
                ]
            }

        ]
        return prompts

    def test_create(self, endpoint, account, prompts, post_endpoint):
        post_schema = post_endpoint.get("schema")
        post_schema = self.fill_schema(post_schema)

        prompts = prompts + [  # Check Permissions for CRUD Operations

            # Create Operation:

            {
                "objective": "Check Permissions for CRUD Operations: Create",
                "steps": [
                    f"Authorized Creation - Send a POST request to {endpoint} with valid data to create a new resource like {post_schema}, using a user with creation permissions. Expect a 201 Created response if successful.",
                    f"Unauthorized Creation - Then, attempt to send a similar request to {endpoint}  like {post_schema} with a user who lacks creation permissions, expecting a 403 Forbidden or similar error response."
                ],
                "path": [endpoint, endpoint],
                "expected_response_code": [
                    "201 Created for successful creation by authorized users, confirming that the system allows creation as expected.",
                    "403 Forbidden for unauthorized creation attempts, confirming that the system properly restricts creation permissions."
                ],
                "token": [account.get("token"), account.get("token")],
                "security": [
                    "Ensure that the system robustly validates user permissions before processing CRUD operations. "
                    "Confirm that only users with the appropriate permissions can create resources, and that unauthorized attempts are correctly identified and denied."]
            }
        ]

        return prompts

    def test_get(self, endpoint, account, prompts):

        get_endpoint, endpoint_of_other_user = self.replace_ids(account, endpoint)

        prompts = prompts + [

            # Read Operation:

            {
                "objective": "Check Permissions for CRUD Operations: Read",
                "steps": [
                    f"Authorized Read - Send a GET request to {get_endpoint} with a user who has read permissions, verifying that the correct data is returned.",
                    f"Unauthorized Read - Attempt the same request to {endpoint_of_other_user} with a user who lacks read permissions, and verify that the response returns a 403 Forbidden or 404 Not Found status."
                ],
                "path": [get_endpoint, get_endpoint],
                "expected_response_code": [
                    "200 OK for successful data retrieval by authorized users, confirming that the system allows reading of data as expected.",
                    "403 Forbidden or 404 Not Found for unauthorized read attempts, confirming that the system properly restricts reading permissions."
                ],
                "token": [account.get("token"), account.get("token")],

                "security": [
                    "Ensure that the system robustly validates user permissions before allowing access to read operations. Confirm that only users with the appropriate permissions can access data, and that unauthorized attempts are correctly identified and denied, preventing data leaks."]
            }]


        return prompts

    def test_put(self, put_endoint, account, prompts):
        endpoint = put_endoint.get("path")
        put_endoint_schema = put_endoint.get("schema")
        put_endoint, endpoint_of_other_user = self.replace_ids(account, endpoint)
        prompts = prompts + [

            # Update Operation:

            {
                "objective": "Check Permissions for CRUD Operations: Update",
                "steps": [
                    f"Authorized Update - Send a PUT or PATCH request to {put_endoint} to update a resource using a user with update permissions. Expect the resource to be modified, indicated by a 200 OK or 204 No Content response schema:{put_endoint_schema}.",
                    f"Unauthorized Update - Then, repeat the request with a user to {endpoint_of_other_user}who lacks update permissions, expecting a 403 Forbidden response."
                ],
                "path": [put_endoint, put_endoint],
                "token": [account.get("token"), account.get("token")],

                "expected_response_code": [
                    "200 OK or 204 No Content for successful modification by authorized users, confirming that the system allows updates as expected.",
                    "403 Forbidden for unauthorized update attempts, confirming that the system properly restricts updating permissions."
                ],
                "security": [
                    "Ensure that the system robustly validates user permissions before allowing access to update operations. Confirm that only users with the appropriate permissions can modify resources, and that unauthorized attempts are correctly identified and denied, preventing unauthorized data modification."]}

        ]
        return prompts

    def test_delete(self, endpoint, account, prompts):
        delete_endpoint, endpoint_of_other_user = self.replace_ids(account, endpoint)

        prompts = prompts + [

            # Delete Operation:

            {
                "objective": "Check Permissions for CRUD Operations: Delete",
                "steps": [
                    f"Authorized Deletion - Send a DELETE request to {delete_endpoint} with a user who has delete permissions, verifying a successful deletion with a 200 OK or 204 No Content response.",
                    f"Unauthorized Deletion - Then, attempt to delete the resource with a user {endpoint_of_other_user} who lacks delete permissions, expecting a 403 Forbidden response."
                ],
                "token": [account.get("token"), account.get("token")],
                "path": [delete_endpoint, delete_endpoint],
                "expected_response_code": [
                    "200 OK or 204 No Content for successful deletion by authorized users, confirming that the system allows deletions as expected.",
                    "403 Forbidden for unauthorized deletion attempts, confirming that the system properly restricts deleting permissions."
                ],
                "security": [
                    "Ensure that the system robustly validates user permissions before allowing access to delete operations. Confirm that only users with the appropriate permissions can delete resources, and that unauthorized attempts are correctly identified and denied, preventing unauthorized resource removal."]
            }]

        return prompts

    def test_access_scope(self, get_endpoint, post_endpoint, put_endpoint, account, prompts):
        if isinstance(get_endpoint, dict):
            get_endpoint = get_endpoint.get("path")
        if isinstance(post_endpoint, dict):
            post_endpoint = post_endpoint.get("path")
        if isinstance(put_endpoint, dict):
            put_endoint = put_endpoint.get("path")
        if "api" in get_endpoint and post_endpoint and put_endpoint:
            if account["api"] in get_endpoint and account["api"] in post_endpoint and account[
                "api"] in put_endpoint:
                id = account.get("id")
                get_endpoint = get_endpoint.replace("{id}", str(account.get("id")))
                post_endoint = post_endpoint.replace("{id}", str(account.get("id")))
                put_endoint = put_endoint.replace("{id}", str(account.get("id")))
                prompts = prompts + [

                    # Access Token Scope Testing
                    {
                        "objective": "Access Token Scope Testing",
                        "steps": [
                            f"Testing Read-Only Scope for Data Retrieval - Send a GET request to {get_endpoint} using a read-only access token. Verify that the response status is 200 OK, allowing data retrieval.",
                            f"Attempting Write Operation with Read-Only Token - Attempt to modify data on {put_endoint} by sending a POST, PUT, or DELETE request using the same read-only access token.",
                            f"Testing Full-Access Token (if applicable) - Send a POST request to {post_endoint} using a full-access token to verify that write actions are permitted."
                        ],
                        "token": [account.get("token"), self.create_random_bearer_token(),
                                  account.get("token")],
                        "path": [get_endpoint, put_endoint, post_endoint],

                        "expected_response_code": [
                            "200 OK for successful data retrieval using a read-only token, confirming the enforcement of read-only access.",
                            "403 Forbidden for attempted write operations with a read-only token, confirming that the token scope correctly restricts write actions.",
                            "200 OK or 201 Created for successful write actions using a full-access token, confirming that full-access privileges are appropriately granted."
                        ],
                        "security": [
                            "Ensure that the a A read-only access token permits data retrieval (GET request).",
                            "The same read-only token denies access to write operations (POST, PUT, DELETE requests).",
                            "A full-access token (if applicable) allows write actions, validating proper enforcement of token scopes."]
                    }
                ]

        else:
            if "id}" in get_endpoint:
                get_endpoint = self.replace_placeholders_with_1(get_endpoint, account.get("id"))
                prompts = prompts + [

                    # Access Token Scope Testing
                    {
                        "objective": "Access Token Scope Testing",
                        "steps": [
                            f"Testing Read-Only Scope for Data Retrieval - Send a GET request to {get_endpoint} using a read-only access token. Verify that the response status is 200 OK, allowing data retrieval.",
                            f"Attempting Write Operation with Read-Only Token - Attempt to modify data on {put_endpoint} by sending a POST, PUT, or DELETE request using the same read-only access token.",
                            f"Testing Full-Access Token (if applicable) - Send a POST request to {post_endpoint} using a full-access token to verify that write actions are permitted."
                        ],
                        "token": [account.get("token"), self.create_random_bearer_token(),
                                  account.get("token")],
                        "path": [get_endpoint, put_endpoint, post_endpoint],

                        "expected_response_code": [
                            "200 OK for successful data retrieval using a read-only token, confirming the enforcement of read-only access.",
                            "403 Forbidden for attempted write operations with a read-only token, confirming that the token scope correctly restricts write actions.",
                            "200 OK or 201 Created for successful write actions using a full-access token, confirming that full-access privileges are appropriately granted."
                        ],
                        "security": [
                            "Ensure that the a A read-only access token permits data retrieval (GET request).",
                            "The same read-only token denies access to write operations (POST, PUT, DELETE requests).",
                            "A full-access token (if applicable) allows write actions, validating proper enforcement of token scopes."]
                    }
                ]
        return prompts

    # This prompt tests that:
    # - A read-only access token permits data retrieval (GET request).
    # - The same read-only token denies access to write operations (POST, PUT, DELETE requests).
    # - A full-access token (if applicable) allows write actions, validating proper enforcement of token scopes.
    def replace_id_placeholder(self, path: str, value: str) -> str:
        return re.sub(r'\{[a-zA-Z0-9_]*_id\}', value, path)

    def test_authentication(self, endpoint, account, prompts):
        if "api" in endpoint:

            new_endpoint, endpoint_of_other_user = self.replace_ids(account, endpoint)

        else:  # Non-API endpoints
            new_endpoint, endpoint_of_other_user = self.replace_ids(account, endpoint)
        prompts = prompts + [  # Check Access Without Authentication
            {
                "objective": "Check Access Without Authentication",
                "steps": [
                    f"make a GET request to the protected endpoint {new_endpoint} without including any authentication headers with user:{account}.\n"],
                "expected_response_code": ["401 Unauthorized", "403 Forbidden."],
                "token": [""],
                "path": [new_endpoint],
                "security": [
                    "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]},
            # Test Valid Authentication
            {
                "objective": "Test Valid Authentication",
                "steps": [
                    f"use this accounts token to send a GET request to {new_endpoint}."],
                "expected_response_code": [
                    "200 OK response, indicating successful authentication."
                ],
                "path": [new_endpoint],
                "token": [account.get("token")],
                "security": ["Verify that the response includes the expected data.",
                             "Confirm that the token provides the correct access level."]

            },
            # Test only can access my user
            {
                "objective": "Test cannot access other user data",
                "steps": [
                    f"use this accounts token to send a GET request to {endpoint_of_other_user}."],
                "expected_response_code": ["401 Unauthorized", "403 Forbidden."],
                "token": [account.get("token")],
                "path": [new_endpoint],
                "security": [
                    "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]},
        ]

        return prompts

    def test_token(self, login_path, endpoint, account, login_schema, prompts, revocation=False):
        if revocation and endpoint is not None:

            prompts.append(

                # Token Revocation
                {
                    "objective": "Token Revocation",
                    "steps": [
                        f"Send a GET request to {endpoint} with a valid token = {account.get('token')}.",
                        f"Send a POST request to the token revocation endpoint {login_path} to invalidate an active token with user credentials:{account}",
                        f"Test the revoked token by sending a GET request to {endpoint} with the revoked token."
                    ],
                    "expected_response_code": [
                        "200 OK for the initial use of the valid token, confirming it is active.",
                        "200 OK or 204 No Content, Successful revocation "
                        "401 Unauthorized for attempts made with the revoked token, confirming the system's capability to recognize and deny access with revoked credentials."
                    ],
                    "token": [account.get("token"), "", account.get("token")],
                    "path": [endpoint, login_path, endpoint],
                    "security":
                        [
                            "Ensure that valid tokens are correctly recognized and granted access, confirming that authentication systems are functioning as expected before revocation.",
                            "Verify that once tokens are revoked, the system immediately denies access, preventing any security breaches that could occur from the continued use of revoked tokens. This includes ensuring timely updates across all components of the system that might interact with token validation processes."]

                }

            )  # protected end point needed
        else:
            prompts = prompts + [
                {  # Test Expired or Invalid Tokens
                    "objective": "Test Expired or Invalid Tokens",
                    "steps": [
                        f"Send a POST request to the login endpoint {login_path} with valid login credentials ({login_schema}) to obtain a valid token with user:{account}.\n",
                        f"Send a GET request to {endpoint} using an expired, revoked, or otherwise invalid token."
                    ],
                    "path": [login_path, endpoint],
                    "expected_response_code": [
                        "200 OK for successfully obtaining a valid token with correct credentials.",
                        "401 Unauthorized for the expired or invalid token, verifying that the system rejects tokens that are no longer valid."
                    ],
                    "token": ["", self.create_random_bearer_token()],
                    "security": [
                        "Ensure that the system appropriately validates token expiration or invalidation before granting access.",
                        "Ensure that no sensitive information is included in the error responses."
                    ]
                },
                # Basic Authentication (if applicable)
                {
                    "objective": "Valid Basic Authentication",
                    "steps": [
                        f"Send a GET request to {endpoint} using Basic Authentication with the valid token {self.valid_token}."
                    ],
                    "path": [endpoint],
                    "expected_response_code": [
                        "200 OK when sending a GET request with correct credentials, confirming access is granted."
                    ],
                    "token": [account.get("token")],
                    "security": [
                        "Ensure the system returns a 200 OK response for valid credentials and does not expose sensitive data in the response body."
                    ]
                },
                {
                    "objective": "Invalid Basic Authentication",
                    "steps": [
                        f"Attempt to send a POST request to the login endpoint {login_path} using invalid login credentials {login_schema} with user:{account}.\n",
                        f"Send a GET request to {endpoint} using Basic Authentication with invalid credentials:{self.get_invalid_credentials(account)}"
                    ],
                    "path": [login_path, endpoint],
                    "expected_response_code": [
                        "401 Unauthorized when attempting to authenticate with invalid credentials.",
                        "401 Unauthorized when attempting to access the protected endpoint with invalid credentials."
                    ],
                    "token": [account.get("token"), account.get("token")],
                    "security": [
                        "Ensure that the system rejects invalid credentials with a 401 Unauthorized status.",
                        "Ensure no sensitive information is leaked in the error responses, such as specific reasons for the failure."
                    ]
                }
                ,

            ]

        return prompts

    def test_refresh_token(self, refresh_post_endpoint, refresh_get_endpoint, account, prompts):
        prompts = prompts + [  # Test Token Refresh (if applicable)

            {
                "objective": "Test Token Refresh",
                "steps": [
                    f"send a GET request to {refresh_get_endpoint} with the expired token in the Authorization header. Verify that the API responds with a 401 Unauthorized status, indicating the token has expired.",
                    f"send a POST request to the token refresh endpoint {refresh_post_endpoint} with the valid refresh token in the request body or headers, depending on the API's token refresh requirements. Check if the API responds with a 200 OK status and includes a new access token in the response body.",
                    f"use the new access token to send a GET request to {refresh_get_endpoint} again. Confirm that the API responds with a 200 OK status, indicating successful access with the refreshed token, and that the old expired token is no longer valid."
                ],
                "path": [refresh_get_endpoint, refresh_get_endpoint, refresh_get_endpoint],
                "token": [self.create_random_bearer_token(),
                          account.get("token"),
                          account.get("token")],
                "expected_response_code": [
                    "401 Unauthorized for the expired token use, verifying that the token has indeed expired and is recognized by the system as such.",
                    "200 OK upon refreshing the token, confirming that the refresh mechanism works as expected and a new token is issued correctly.",
                    "200 OK when using the new token, verifying that the new token grants access and the old token is invalidated."
                ],
                "security": [
                    "Ensure that the API does not leak sensitive information in error responses and that expired tokens are promptly invalidated to prevent unauthorized use."]
            }

            # This prompt tests if the API correctly handles token expiration and issues a new token upon refresh,
            # while ensuring that the expired token no longer provides access to protected resources.

        ]
        return prompts

    def test_crud(self, endpoints, prompts):
        post_endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "POST")
        delete_endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "DELETE")
        put_endpoints = self.get_correct_endpoints_for_method("protected_endpoint", "PUT")

        for account in self.accounts:

            if "id" in account.keys():
                id = account.get("id")
            else:
                id = 1

            for post_endpoint in post_endpoints:

                if "api" in post_endpoint and len(post_endpoint.split("/")) > 0:
                    if account["api"] in post_endpoint:
                        endpoint = post_endpoint.replace("{id}", str(account.get("id")))
                        prompts = self.test_create(endpoint, account, prompts, post_endpoint=post_endpoint)

                    else:
                        prompts = self.test_create(post_endpoint.get("path"), account, prompts,
                                                   post_endpoint=post_endpoint)
                else:
                    prompts = self.test_create(post_endpoint.get("path"), account, prompts, post_endpoint)

            for get_endpoint in endpoints:
                if isinstance(get_endpoint, dict):
                    get_endpoint = get_endpoint.get("path")

                if "api" in get_endpoint and "id" in account.keys():
                    if account["api"] in get_endpoint and isinstance(account["id"], int):

                        prompts = self.test_get(get_endpoint, account, prompts)

                    else:
                        prompts = self.test_get(get_endpoint, account, prompts)

                else:
                    if "{id}" in get_endpoint:

                        id = 1
                        if "OWASP" in self.config.get("name") and "basket" not in get_endpoint:
                            continue

                        prompts = self.test_get(get_endpoint, account, prompts)

            for put_endoint in put_endpoints:
                if "api" in put_endoint:
                    if account["api"] in put_endoint:
                        prompts = self.test_put(put_endoint, account, prompts)
                else:

                    prompts = self.test_put(put_endoint, account, prompts)

            for delete_endpoint in delete_endpoints:
                id = 2
                if isinstance(delete_endpoint, dict):
                    delete_endpoint_schema = delete_endpoint.get("schema")
                    delete_endpoint = delete_endpoint.get("path")
                if "api" in delete_endpoint and "id" in delete_endpoint:
                    prompts = self.test_delete(delete_endpoint, account, prompts)
                else:
                    prompts = self.test_delete(delete_endpoint, account, prompts)

            for get_endpoint in endpoints:
                for post_endpoint in post_endpoints:
                    for put_endpoint in put_endpoints:
                        prompts = self.test_access_scope(get_endpoint, post_endpoint, put_endpoint, account, prompts)

        return prompts

    def test_injection_bender_account(self, login_path, prompts):
        injection_account = None
        bender_account = None
        if "OWASP" in self.config.get("name"):
            injection_account = {"email": "' or 1=1--", "password": "a", "x": self.counter}
            self.counter = self.counter + 1
            bender_account = self.config.get("bender")
            bender_account["x"] = self.counter + 1
        if injection_account is not None:
            prompts.append({
                "objective": "SQL Injection Attack on Login (Administrator Account)",
                "steps": [
                    f"Send a POST request to {login_path} with user:{injection_account}.\n"
                ],
                "token": [""],
                "path": [login_path],
                "expected_response_code": [
                    "400", "404", "403"
                ],
                "security": [
                    "Ensure that input fields like the login form are properly sanitized to prevent SQL injection attacks.",
                    "Implement prepared statements or parameterized queries to eliminate the possibility of SQL injection exploitation.",
                    "Verify that authentication systems prevent unauthorized login by enforcing strict checks on input data."
                ]
            }

            )
        if bender_account is not None:
            prompts.append({
                "objective": "SQL Injection Attack on Login (Bender Account)",
                "steps": [
                    f"Send a POST request to {login_path} with user:{bender_account}.\n"
                ],
                "token": [""],
                "path": [login_path],
                "expected_response_code": [
                    "400", "404", "403"
                ],
                "security": [
                    "Ensure that input fields like the login form are properly sanitized to prevent SQL injection attacks.",
                    "Implement prepared statements or parameterized queries to eliminate the possibility of SQL injection exploitation.",
                    "Verify that authentication systems prevent unauthorized login by enforcing strict checks on input data."
                ]
            }
            )
        return prompts

    def test_brute_force(self, login_path, login_schema, prompts, number=100):
        if number == 10:

            str = [
                      f"Attempt Login with Invalid Credentials - Send repeated POST requests to the login endpoint {login_path} using invalid credentials (e.g., incorrect password) {self.get_credentials(login_schema, login_path)}. " +
                      f"Simulate a high rate of attempts (e.g., 10 requests within 1 minute) to trigger potential brute force protection mechanisms. "] * 10

            prompts.append(  # Brute Force Protection
                {
                    "objective": "Brute Force Protection",
                    "steps": str,
                    "expected_response_code":
                        [[
                            "429 Too Many Requests to indicate effective rate-limiting measures against brute force attacks.",
                            "403 Forbidden as an alternative response indicating account lockout or other security measures preventing further attempts."
                        ]] * 10,
                    "token": [""] * 10,
                    "path": [login_path] * 10,
                    "security":
                        ["Ensure that user cannot login with invalid credentials.\n" +
                         "Ensure that rate-limiting mechanisms are robust and properly configured to prevent brute force attacks by limiting the number of allowed failed attempts within a given time frame. This prevents attackers from trying a large number of combinations in a short period.\n" +
                         "Check that account lockout mechanisms or other access denial policies are effective in disabling further login attempts after a certain number of failures, protecting against continuous brute force attempts and securing user accounts from unauthorized access."]

                }
            )
        else:
            if len(self.brute_force_accounts) > 0:
                for acc_b in self.brute_force_accounts:
                    acc_b["x"] = 100
                    str = [
                              f"Attempt Login with different Credentials - Send repeated POST requests to the login endpoint {login_path} using invalid credentials (e.g., incorrect password) user:{acc_b}.\n" +
                              f"Simulate a high rate of attempts (e.g., 10 requests within 1 minute) to trigger potential brute force protection mechanisms. "] * 10

                    prompts.append(  # Brute Force Protection
                        {
                            "objective": "Brute Force Attack",
                            "steps": str,
                            "expected_response_code":
                                [
                                    "429 Too Many Requests to indicate effective rate-limiting measures against brute force attacks.",
                                    "403 Forbidden as an alternative response indicating account lockout or other security measures preventing further attempts."
                                ] * 10,
                            "token": [""] * 10,
                            "path": [login_path] * 10,
                            "security":
                                ["Ensure that user cannot login with invalid credentials.\n" +
                                 "Ensure that rate-limiting mechanisms are robust and properly configured to prevent brute force attacks by limiting the number of allowed failed attempts within a given time frame. This prevents attackers from trying a large number of combinations in a short period.\n" +
                                 "Check that account lockout mechanisms or other access denial policies are effective in disabling further login attempts after a certain number of failures, protecting against continuous brute force attempts and securing user accounts from unauthorized access."]

                        }
                    )

            change_email = self.extract_change_email_endpoints_with_schema()
            for endpoint, schema in change_email:
                for account in self.accounts:
                    if isinstance(endpoint, dict):
                        schema = endpoint.get("schema")
                        schema = self.fill_schema(schema)
                    else:
                        schema = self.fill_schema(schema)
                        prompts.append(  # Insecure Email Change Process
                            {
                                "objective": "Insecure Email Change Process",
                                "steps": [f"Send a POST request to endpoint {endpoint} with schema {schema}"],
                                "expected_response_code":
                                    [
                                        "403 Forbidden if proper authorization checks prevent changing another user's email."
                                    ],
                                "token": [account.get("token")],
                                "path": [endpoint],
                                "security":
                                    [
                                        "Ensure that users cannot change the email address of other users without proper authorization.\n" +
                                        "Verify that sensitive actions like email changes send verification tokens only to the current, verified email address of the account owner.\n" +
                                        "Check for IDOR vulnerabilities and enforce proper ownership validation when modifying sensitive user information."]
                            }
                        )

            otp_endpoints = [ep for ep in self.endpoints if "otp"]
            reset_password = [ep for ep in self.endpoints if
                              "reset" or "password" or "forget-password" or "forgot" in ep]
            otps = list(range(0000, 9999))
            random_otps = [8859] + random.sample(otps, 10)
            otp_calls = ""
            counter = 0
            otps = []
            for (otp, otp_endpoint) in zip(random_otps, otp_endpoints):
                otp_request = {"email": "adam007@example.com", "otp": f'{otp}', "password": "Az123###"}

                otp_calls = otp_calls + f"Send a POST request to endpoint {otp_endpoint} with the following body {otp_request}.\n"
                counter += 1
                otps.append(otp)

            for reset in reset_password:
                user = {"email": "adam007@example.com"}
                # triggers otp being sent
                new_otp_calls = f"Send a POST request to endpoint{reset} for victim user:{user}.\n" + otp_calls
                prompts.append(  # OTP Bruteforce Protection
                    {
                        "objective": "OTP Bruteforce Protection",
                        "steps": [new_otp_calls],
                        "expected_response_code":
                            [
                                "429 Too Many Requests indicating effective rate-limiting against OTP bruteforce attempts.",
                                "403 Forbidden indicating account lockout or blocking after multiple failed OTP attempts."
                            ] * counter,
                        "token": [""] * counter,
                        "path": [reset] + otps,
                        "security":
                            [
                                "Ensure that OTP verification mechanisms enforce rate-limiting to prevent brute-force attacks.\n" +
                                "Verify that deprecated or older API versions do not bypass security controls.\n" +
                                "Ensure consistent security protections across all API versions to prevent attackers from exploiting outdated endpoints."]
                    }
                )

        return prompts

    def extract_change_email_endpoints_with_schema(self) -> list[tuple]:
        """
        Extracts all endpoints containing 'change-email' and returns (path, schema) pairs.

        Returns:
            list: List of tuples (path, schema) for change-email endpoints.
        """
        result = []

        for path, methods in self.endpoints.items():
            if "change-email" in path:
                for method, method_detail in methods.items():
                    schema = method_detail.get("requestBody", {}).get("content", {}).get("application/json", {}).get(
                        "schema")
                    result.append((path, schema))

        return result

    def test_css(self, endpoint, prompts, schema=None):
        if schema:
            prompts.append(

                # Cross-Site Scripting Protection (for OAuth)
                {
                    "objective": "Cross-Site Scripting Protection (for OAuth)",
                    "steps": [
                        f" Alter Redirect URI in OAuth Request - Send an OAuth authentication request to the endpoint {endpoint} based on schema {schema} with a modified redirect URI that differs from the registered URI. The redirect URI in the request should be altered to a different URL (e.g., https://malicious.site/redirect) to test if the API enforces a strict redirect policy. This step tests if the API strictly validates the redirect URI in OAuth flows, preventing open redirection vulnerabilities.",
                    ],
                    "token": [""],
                    "path": [endpoint],
                    "expected_response_code": [
                        "400 Bad Request or 403 Forbidden to indicate successful rejection of unauthorized or mismatched redirect URIs in OAuth requests."
                    ],
                    "security": {
                        [
                            "Ensure that the OAuth service correctly identifies and rejects requests where the redirect URI does not match the one registered with the client ID. This is crucial to prevent attackers from exploiting open redirection vulnerabilities."
                            "Verify that the security configuration effectively blocks unauthorized attempts to redirect users to malicious sites through OAuth requests. This protects users from potential cross-site scripting (XSS) attacks and unauthorized data access."]
                    }
                }

            )
        else:
            prompts.append(

                # Cross-Site Scripting Protection (for OAuth)
                {
                    "objective": "Cross-Site Scripting Protection (for OAuth)",
                    "steps": [
                        f" Alter Redirect URI in OAuth Request - Send an OAuth authentication request to the endpoint {endpoint} with a modified redirect URI that differs from the registered URI. The redirect URI in the request should be altered to a different URL (e.g., https://malicious.site/redirect) to test if the API enforces a strict redirect policy. This step tests if the API strictly validates the redirect URI in OAuth flows, preventing open redirection vulnerabilities.",
                    ],
                    "expected_response_code": [
                        "400 Bad Request or 403 Forbidden to indicate successful rejection of unauthorized or mismatched redirect URIs in OAuth requests."
                    ],
                    "token": [""],
                    "path": [endpoint],
                    "security": {
                        [
                            "Ensure that the OAuth service correctly identifies and rejects requests where the redirect URI does not match the one registered with the client ID. This is crucial to prevent attackers from exploiting open redirection vulnerabilities."
                            "Verify that the security configuration effectively blocks unauthorized attempts to redirect users to malicious sites through OAuth requests. This protects users from potential cross-site scripting (XSS) attacks and unauthorized data access."]
                    }
                }

            )

        return prompts

    def test_comment(self, account, prompts):
        comment_endpoint = self.get_comment_ep()
        if comment_endpoint:
            prompts = prompts + [
                {
                    "objective": "Excessive data exposure",
                    "steps": [
                        f"Send a GET request to {comment_endpoint} with a valid token = {account.get('token')}.",
                    ],
                    "expected_response_code": [
                        "200 OK for the initial use of the valid token, confirming it is active.",
                    ],
                    "token": [account.get("token")],
                    "path": [comment_endpoint],
                    "security":
                        [
                            "Ensure that there is only one id in the response."]

                }
            ]
        return prompts

    def test_sql_injection(self, account, endpoint, schema, prompts):
        params = [{"username": "' OR 1=1 #", "password": "password"},
                  {"username": "'", "password": "password"},
                  {"username": "admin", "password": "'"}]
        for param in params:
            schema = self.fill_schema(schema, param)
            if schema != {} or len(schema) != 0:

                if "example" in schema:
                    schema = schema.get("example")
                    if "{{" in schema:
                        continue
                prompts = prompts + [
                    # Test for Common Injection Vulnerabilities
                    {
                        "objective": "Test for Common Injection Vulnerabilities",
                        "steps": [
                            f"Send a POST request to exploit common injection vulnerabilities by sending malicious input to {endpoint} based on the schema {schema}."
                        ],
                        "token": [account.get("token")],
                        "path": [endpoint],
                        "expected_response_code": [
                            "400 Bad Request,API detects syntactically incorrect inputs due to malformed SQL queries",
                            "403 Forbidden,API recognizes the input as an unauthorized attempt to access or manipulate data",
                            "422 Unprocessable Entity (if using WebDAV extensions of HTTP): This is suitable for cases where the request format is correct, but the content includes manipulative commands or data that the server refuses to process."
                        ],
                        "security": [
                            "Ensure the API has measures in place to detect and neutralize injection attacks, securing the application from malicious input manipulation."
                        ]
                    }]

        return prompts

    def test_inputs(self, post_endpoint, schema, account, prompts):
        xss_user = '{"email": "<script>alert(\\"XSS2\\")</script>", "password": ""}'
        example = {'field1': 'value1', 'field2': 123}

        prompts = prompts + [

            # Test Valid Data Input

            {
                "objective": "Test Valid Data Input",
                "steps": [
                    f"Send a POST request to {post_endpoint} with a payload that matches the valid schema {schema}. This step verifies that the API can correctly process and accept valid data as expected.",
                ],
                "expected_response_code": [
                    "200 OK",
                    "201 Created indicating that the input data is valid and successfully processed by the API."
                ],
                "path": [post_endpoint],
                "token": [account.get("token")],
                "security":
                    [
                        "Ensure data validation mechanisms are robust to prevent malformed or malicious data entries. This involves confirming that all input adheres to the expected schema and triggers appropriate responses, which is critical for maintaining the integrity and security of the application."
                    ]}
            # This request tests that the API processes valid data successfully and as expected.
            ,

            # Test Invalid Data Input
            {
                "objective": "Test Invalid Data Input",
                "steps": [
                    f"send a POST request to {post_endpoint} with a payload that violates the schema {schema}. An example of an invalid payload might be: {example}, where data types or required fields are incorrect. This step tests the API's ability to validate data against the schema and handle errors.",
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    [
                        "400 Bad Request indicating that the API correctly identifies invalid data inputs and rejects them, as per the validation rules defined in the schema."]
                ],
                "security":
                    [
                        "Ensure that the API's input validation mechanisms are effectively safeguarding against malformed, incorrect, or maliciously crafted data. Robust validation is essential for preventing data integrity issues and securing the API from common vulnerabilities such as injection attacks."
                    ]}

            # This request tests the API’s response to invalid data, ensuring it properly rejects malformed input.
            ,

            # Test Edge Case Data Input
            {
                "objective": "Test Valid Edge Case Data Input",
                "steps": [
                    f"send a POST request to {post_endpoint} with valid edge case values based on the schema {schema}. Examples of valid edge case payloads might include: {{'field1': 'short', 'field2': 1}}, testing the system's handling of minimal valid inputs."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "200 OK",
                    "201 Created status, confirming that it can gracefully handle edge cases within the expected boundaries."
                ],
                "security":
                    [
                        "Ensure that the API's handling of valid edge cases adheres to expected data integrity rules and does not trigger any exceptions or errors, maintaining the reliability and security of the system."
                    ]},
            {
                "objective": "Test Invalid Edge Case Data Input",
                "steps": [
                    f"send a POST request to {post_endpoint} with invalid edge case values that clearly violate the boundaries defined by the schema {schema}. Examples of invalid edge case payloads might include: {{'field1': '', 'field2': -999999999999}}, testing the system's ability to reject inputs that are out of acceptable range or format."
                ],
                "path": [post_endpoint],
                "token": [account.get("token")],
                "expected_response_code": [
                    "400 Bad Request, confirming that it enforces data constraints and effectively manages inputs that could lead to potential vulnerabilities."
                ],
                "security":
                    [
                        "Verify that the API's error handling for invalid edge cases prevents data corruption, unhandled exceptions, and security vulnerabilities, such as buffer overflows or other unexpected behaviors that could compromise system stability."
                    ]}

            # This request tests if the API can handle extreme values or edge cases without errors.
            ,

            # Test Missing Required Fields
            {
                "objective": "Test Missing Required Fields",
                "steps": [
                    f"Send a POST request to {post_endpoint} omitting required fields based on {schema}. Example payload: {{'field1': 'value1'}} (missing 'field2'). This tests the API's ability to enforce required fields and provide feedback on missing data."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, specifying the missing fields, confirming that the API enforces data completeness."
                ],
                "security": [
                    "Verify that the API's error handling for missing required fields prevents data processing issues and maintains integrity."
                ]
            }

            # This request tests if the API enforces required fields and provides feedback on missing data.
            ,

            # Test Special Characters and Injection Attacks
            {
                "objective": "Test Special Characters and Injection Attacks",
                "steps": [
                    f"Send a POST request to {post_endpoint} with potentially malicious data, such as SQL or XSS payloads in fields based on the schema {schema} . Example payload: {{'field1': '<script>alert(1);</script>', 'field2': '1 OR 1=1'}}. This tests the API's ability to sanitize inputs to prevent injection attacks.user: {xss_user}.\n"
                ],
                "path": [post_endpoint],
                "token": [account.get("token")],

                "expected_response_code": [
                    "200 OK, API sanitizes the input",
                    "400 Bad Request,API recognizes the input as malicious and rejects the request ",
                    " 403 Forbidden,API recognizes the input as malicious and rejects the request "
                ],
                "security": [
                    "Check that the API effectively sanitizes and neutralizes special characters and injection vectors to secure data handling."
                ]
            }

            # This request tests if the API sanitizes inputs to prevent injection attacks.
            ,

            # Test Incorrect Data Format
            {
                "objective": "Test Special Characters and Injection Attacks",
                "steps": [
                    f"Send a POST request to {post_endpoint} with potentially malicious data, such as SQL or XSS payloads in fields based on the schema {schema}. Example payload: {{'field1': '<script>alert(1);</script>', 'field2': '1 OR 1=1'}}. This tests the API's ability to sanitize inputs to prevent injection attacks."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "200 OK, API sanitied input",
                    "400 Bad Request, API recognizes input as malicious data.",
                    "403 Forbidden, API recognizes input as malicious data. "
                ],
                "security": [
                    "Check that the API effectively sanitizes and neutralizes special characters and injection vectors to secure data handling."
                ]
            }

            # This request tests if the API validates data formats and rejects incorrect data types.
            ,

            # General Error Handling and Response Code Check
            {
                "objective": "General Error Handling and Response Code Check",
                "steps": [
                    f"Send POST requests with a range of invalid inputs to {post_endpoint} to test the API's error handling consistency based on the schema {schema}. Example payloads include missing fields, incorrect types, and special characters. This tests if the API consistently uses appropriate HTTP status codes and provides clear error messages."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request for syntactically incorrect data or missing fields",
                    "422 Unprocessable Entity for correct format but semantically erroneous data (if applicable)"
                ],
                "security": [
                    "Check that the API's error responses do not expose sensitive information while providing helpful error context."
                ]
            }

            # This request tests if the API uses consistent HTTP codes and provides clear error messages for invalid inputs.
            ,

            # Test for Common Injection Vulnerabilities
            {
                "objective": "Test for Common Injection Vulnerabilities",
                "steps": [
                    f"Send a POST request to exploit common injection vulnerabilities by sending malicious input to {post_endpoint} based on the schema {schema}. Example payload: {{'field1': \"'; DROP TABLE users; --\"}}. This tests the API’s defenses against SQL injection and other forms of injection."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request,API detects syntactically incorrect inputs due to malformed SQL queries",
                    "403 Forbidden,API recognizes the input as an unauthorized attempt to access or manipulate data",
                    "422 Unprocessable Entity (if using WebDAV extensions of HTTP): This is suitable for cases where the request format is correct, but the content includes manipulative commands or data that the server refuses to process."
                ],
                "security": [
                    "Ensure the API has measures in place to detect and neutralize injection attacks, securing the application from malicious input manipulation."
                ]
            }

            # This request tests the API’s resistance to injection attacks, ensuring input handling is secure.
            ,

            # Validate Data Sanitization and Security
            {
                "objective": "Validate Data Sanitization and Security",
                "steps": [
                    f"Send a POST request with data containing special characters and potentially harmful inputs to {post_endpoint} based on the schema {schema}. Confirm that the API sanitizes and escapes all data properly."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "Ensure no vulnerabilities are exposed through unsanitized inputs."
                ],
                "security": [
                    "Verify comprehensive sanitization across all input fields to prevent security risks associated with unescaped data."
                ]
            }

            # This request checks that the API applies appropriate sanitization to user-supplied data across all fields.

        ]

        return prompts

    def test_error_handling(self, post_endpoint, account, schema, prompts):
        prompts = prompts + [

            # Test Error Handling with Invalid Input
            {
                "objective": "Test Error Handling with Invalid Input",
                "steps": [
                    f"Send a POST request to {post_endpoint} with deliberately invalid input to test error handling capabilities based on the schema {schema}. Example payload: {{'nonexistent_field': 'invalid_value'}}. This tests the API's ability to recognize and reject invalid input formats or unexpected fields."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, confirming that the API correctly identifies invalid input and provides a clear, informative error message indicating why the input is invalid."
                ],
                "security": [
                    "Ensure the API's error handling mechanisms do not expose sensitive information while adequately informing the user about the nature of the error. This is crucial for maintaining user trust and preventing potential security issues related to erroneous input handling."
                ]
            }

            # This request tests if the API correctly handles invalid input with appropriate error messages and status codes.
            ,

            # Test Error Handling with Missing Required Fields
            {
                "objective": "Test Error Handling for Missing Required Fields",
                "steps": [
                    f"Send a POST request to {post_endpoint} omitting one or more required fields to test the API’s validation mechanisms based on the schema {schema}. Example payload: {{'optional_field': 'test_value'}}, where only optional fields are provided, and required fields are deliberately left out."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, confirming that the API correctly identifies the lack of required fields and responds with a detailed error message that lists the missing required fields."
                ],
                "security": [
                    "Ensure that the API's error responses for missing required fields are specific enough to guide the user but do not disclose sensitive system information that could be exploited."
                ]
            }

            # This request checks if the API enforces required fields and gives helpful feedback on missing data.
            ,

            # Examine Error Message Detail for Information Leakage
            {
                "objective": "Examine Error Message Detail for Information Leakage",
                "steps": [
                    f"Send a POST request to {post_endpoint} with incorrect field types or values to provoke an error response from the API v. Example payload: {{'field': 123}}, where the API is expected to receive a string instead. This step tests the API's handling of data type errors and its error messaging security."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, and scrutinize the error message and headers to ensure they do not disclose sensitive information such as stack traces, server configurations, or detailed server internals."
                ],
                "security": [
                    "Assess the security posture of the API by checking that error responses are safely managed. Error messages and headers should convey enough information for user correction without revealing details that could be used maliciously. Confirm that the error responses maintain privacy and security by not exposing detailed system data."
                ]
            }

            # This request tests if the API avoids leaking sensitive information through error messages or headers.
            ,

            # Test Error Response for Security Vulnerabilities
            {
                "objective": "Test Error Response for Security Vulnerabilities",
                "steps": [
                    f"Send various malformed requests to {post_endpoint} to assess the security of the API's error handling based on the schema {schema}. Example of a malformed request: {{field': 'value' (note the missing closing brace). This tests if the API avoids exposing internal structures or sensitive information in its responses to such requests.}}"
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, without any specific error details that could assist in crafting further attacks."
                ],
                "security": [
                    "Ensure that the API responds with generic error messages that do not disclose any details about the internal workings or structures of the system. Appropriate responses might include a , "
                    "Confirm that error messages are standardized and vague enough to prevent revealing any technical details of the backend systems, such as software versions, frameworks, or detailed error diagnostics. This helps in mitigating risks associated with information leakage."
                ]
            }

            # This request confirms that malformed requests are handled securely and don’t expose implementation details.
            ,

            # Assess Error Messages for Corrective Action Suggestions
            {
                "objective": "Assess Error Messages for Corrective Action Suggestions",
                "steps": [
                    f"Send a POST request to {post_endpoint} with intentionally incorrect inputs such as missing required fields or wrong data types based on the schema {schema}. Example payload could include: {{'field1': 'value1'}} with 'field2' missing or incorrectly formatted. This tests the API's ability to not only catch errors but also guide users towards resolving them."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, fails validation checks such as missing required fields or incorrect data types",
                    "422 Unprocessable Entity, entity is correct but was unable to process the contained instruction"
                ],
                "security": [
                    "Verify that the API's error messages are informative and instructive, providing specific suggestions for correcting the input. Expect responses such as 400 Bad Request that include details on what is missing or incorrect, like specifying missing fields or incorrect data types."
                    "Ensure that while the error messages are helpful, they do not disclose sensitive information or details about the underlying implementation that could be exploited by an attacker. The messages should strike a balance between being helpful and maintaining security."
                ]
            }

            # This request tests if the API offers actionable feedback to help users correct their requests.
            ,

            # Look for Information Leakage Vulnerabilities
            {
                "objective": "Look for Information Leakage Vulnerabilities",
                "steps": [
                    f"Send POST requests to {post_endpoint} with unexpected input, such as special characters or SQL-like strings, to test how securely the API handles error-prone or potentially malicious data based on the schema {schema}. Example payloads could include: {{'field': \"' OR '1'='1\"}} or {{'field': '<script>alert(\"test\");</script>'}}. This tests the API's resilience against attempts to expose sensitive information."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "400 Bad Request, indicating that the input was syntactically incorrect or otherwise unacceptable,",
                    "500 Internal Server Error, if unexpected input leads to unhandled errors within the server"
                ],
                "security": [
                    "Inspect if the response contains any server details, stack traces, or database error messages that could be exploited. The API should not reveal such information under any circumstance. Responses should be sanitized to prevent leakage of sensitive details about the server or the application's internal mechanics.",
                    "Ensure that the error handling is secure and does not inadvertently disclose sensitive information through error messages or HTTP headers. Error responses should be generic and non-descriptive to avoid aiding potential attackers."
                ]
            }

            # This request verifies that the API is secure against accidental exposure of sensitive information in responses.

        ]

        return prompts

    def test_session_management(self, get_endpoint, account, prompts):
        prompts = prompts + [
            {
                "objective": "Check if API Uses Session Management",
                "steps": [
                    f"Send a GET request to {get_endpoint} without authentication.",

                ],
                "path": [get_endpoint],
                "token": [account.get("token")],
                "expected_response_code": [
                    "200 OK if no authentication is required, and the endpoint provides public data.",
                    "401 Unauthorized if authentication is required and no session token or cookie is issued."
                ],
                "security": [
                    "Observe the response headers to check if any session token or cookie is issued.",
                    "Inspect both request and response headers for session-related identifiers."
                    "Ensure that session tokens are not issued unnecessarily, as this could expose vulnerabilities or allow unintended session management."
                ]
            }]
        return prompts

    def test_session_hijacking(self, login_path, get_endpoint, login_schema, account, prompts):
        prompts = prompts + [

            # This prompt tests if the API uses session management by observing session tokens or cookies in responses after a GET request.
            # Test for Session Hijacking Vulnerability
            {
                "objective": "Test for Session Hijacking Vulnerability",
                "steps": [
                    f"Send a POST request to {login_path} with valid credentials {self.get_credentials(login_schema, login_path)} to obtain a session token or cookie.",
                    f"Send a GET request to {get_endpoint} with the session token or cookie and verify if access is granted without re-authentication."
                ],
                "path": [login_path, get_endpoint],
                "expected_response_code": [
                    "401 Unauthorized if the session token is invalid or the system detects unauthorized usage.",
                    "403 Forbidden if the API identifies and blocks an unauthorized attempt to use a session token from a different environment or device."
                ],
                "token": ["", account.get("token"), account.get("token")],
                "security": [
                    "Ensure that the API has mechanisms such as IP binding or device fingerprinting to detect and prevent session hijacking attempts."
                ]
            }
            # This prompt tests for session hijacking by attempting to reuse a session token from a different environment.
            ,
            # Check Session Timeout Settings
            {
                "objective": "Check Session Timeout Settings",
                "steps": [
                    f"Start a session by sending a POST request to {login_path} based on schema {login_schema} and obtaining a session identifier.",
                    "Leave the session idle for the defined timeout period.",
                    f"Send a GET request to {get_endpoint} using the same session token or cookie.",
                ],
                "token": ["", account.get("token"), account.get("token")],
                "path": [login_path, get_endpoint, get_endpoint],
                "expected_response_code": [
                    "401 Unauthorized if the session has expired and the token is rejected due to inactivity.",
                    "403 Forbidden if the API enforces access denial due to an expired session."
                ],
                "security": [
                    "Verify if the session has expired and access is rejected."
                    "Ensure that session timeout settings are enforced to minimize the risk of unauthorized access due to prolonged inactivity."
                ]
            }

            # This prompt tests session timeout by verifying if a session expires after inactivity.
            ,

        ]

        return prompts

    def test_cookies(self, login_path, login_schema, prompts, account=None):
        if account:

            prompts.append(  # Check for SameSite Attribute on Cookies
                {
                    "objective": "Check for SameSite Attribute on Cookies",
                    "steps": [
                        f"Send a POST request to {login_path} based on schema {login_schema} with account {account} to authenticate and obtain a session cookie.",

                    ],
                    "path": [login_path],
                    "token": [""],
                    "expected_response_code": [
                        "200 OK if the session cookie is successfully issued with appropriate attributes.",
                    ],
                    "security": [
                        "Inspect the cookie attributes in the response headers to confirm that the SameSite attribute is set.",
                        "Verify if the SameSite attribute is set to Strict or Lax, ensuring restricted cookie transmission across sites.",
                        "Ensure that the SameSite attribute is configured to mitigate CSRF attacks by limiting cookie transmission.",
                        "Verify that cookies with SameSite set to None also include the Secure attribute to prevent transmission over insecure connections."
                    ]
                }

                # This prompt checks if the API enforces CSRF protection by setting the SameSite attribute on cookies.
            )
        else:
            prompts = prompts + [  # Test for Secure Session Cookie Settings
                {
                    "objective": "Test for Secure Session Cookie Settings",
                    "steps": [
                        f"Send a POST request to {login_path} to obtain a session cookie based on schema {self.get_credentials(login_schema, login_path)} .",
                    ],
                    "token": [""],
                    "path": [login_path],

                    "expected_response_code": [
                        "200 OK if the session cookie includes secure attributes such as HttpOnly and Secure."
                    ],
                    "security": [
                        "Inspect the session token or cookie in the response headers to verify the inclusion of secure attributes such as HttpOnly and Secure."
                        "Ensure that session cookies are configured with secure attributes to prevent unauthorized access or transmission of sensitive session information."
                    ]
                }]

        # This prompt tests for secure session cookie attributes, such as HttpOnly and Secure, to protect against client-side access and enforce secure transmission.
        return prompts

    def test_sessions_vulnerabilitiy(self, login_path, login_schema, account, prompts):
        endpoints = self.get_correct_endpoints_for_method("protected_endpoint",
                                                          "POST") + self.get_correct_endpoints_for_method(
            "public_endpoint", "POST")

        for post_endpoint, _, _ in endpoints:
            prompts = prompts + [

                # Examine Session Handling Mechanism for Session Fixation Vulnerability
                {
                    "objective": "Examine Session Handling Mechanism for Session Fixation Vulnerability",
                    "steps": [
                        f"Authenticate and obtain a session identifier (token or cookie) by sending a POST request to {login_path} based on schema {self.get_credentials(login_schema, login_path)} .",
                        f"Reuse the same session identifier across different sessions or user accounts by sending additional POST requests to {post_endpoint} with this session ID.",
                    ],
                    "token": ["", account.get("token")],
                    "path": [login_path, post_endpoint],

                    "expected_response_code": [
                        "401 Unauthorized if the reused session identifier is invalid or has been appropriately invalidated.",
                        "403 Forbidden if the API detects misuse or an unauthorized attempt to reuse the session."
                    ],
                    "security": [
                        "Check if the session ID remains valid across multiple sessions or accounts."
                        "Verify that the API generates new session identifiers upon login or account change to prevent session fixation attacks."
                    ]
                }

                # This prompt tests for session fixation by reusing a session identifier across multiple login attempts.
                ,

            ]

        return prompts

    def test_xss(self, post_endpoint, account, schema, prompts):
        prompts = prompts + [
            # Test for XSS by Injecting Script into Text Fields
            {
                "objective": "Test for XSS by Injecting Script into Text Fields",
                "steps": [
                    f"Send a POST request to {post_endpoint} where user input is accepted (e.g., comment or message fields) based on schema {schema}."
                    "Include a payload with a script tag, such as <script>alert('XSS');</script>, in the request body to test if the API escapes or sanitizes it correctly."
                ],
                "path": [post_endpoint],
                "token": [account.get("token")],

                "expected_response_code": [
                    "200 OK if the input is safely sanitized and stored.",
                    "400 Bad Request if the payload is outright rejected due to validation rules."
                ],
                "security": [
                    "Verify that the API escapes or sanitizes all user inputs to prevent reflected XSS attacks.",
                    "Ensure that the response does not include any unescaped or executable scripts."
                ]
            }

            # This prompt tests if the API properly sanitizes user inputs in text fields to prevent reflected XSS attacks.
            ,  # Test for Persistent XSS
            {
                "objective": "Test for Persistent XSS",
                "steps": [
                    f"Send a POST request to {post_endpoint} to store user-provided data (e.g., profile descriptions or comments) based on schema {schema}."
                    "Inject a persistent XSS payload, like <script>alert('Persistent XSS');</script>, in the request body."
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "200 OK if the input is safely sanitized and stored without executing any scripts.",
                    "400 Bad Request if the input is rejected due to validation rules."
                ],
                "security": [
                    "Ensure that the API sanitizes or escapes all stored user inputs to prevent stored XSS attacks.",
                    "Verify that scripts in stored content are not executed when retrieved."
                ]
            }

            # This prompt tests if the API prevents stored XSS by sanitizing inputs that might be displayed to other users.
            ,

        ]
        return prompts

    def test_xss_query(self, get_endpoint, account, prompts):
        prompts = prompts + [
            # Check for XSS in Query Parameters
            {
                "objective": "Check for XSS in Query Parameters",
                "steps": [
                    f"Send a GET request to {get_endpoint} with a query parameter containing a script payload, such as ?search=<script>alert('XSS');</script>.",
                ],
                "token": [account.get("token")],
                "path": [get_endpoint],
                "expected_response_code": [
                    "200 OK if the payload is properly sanitized and reflected without execution.",
                    "400 Bad Request if the API blocks the input due to validation rules."
                ],
                "security": [
                    "Ensure that all query parameters are sanitized or escaped to prevent reflected XSS attacks.",
                    "Verify that the response does not contain unescaped scripts or unsafe data."
                ]
            }

            # This prompt tests if the API properly handles and escapes query parameters to prevent reflected XSS.
            ,
            # Test for XSS in JSON Responses
            {
                "objective": "Test for XSS in JSON Responses",
                "steps": [
                    f"Send a GET request to {get_endpoint} expecting a JSON response."
                    "Inject a payload in a query parameter (e.g., ?param=<script>alert('XSS');</script>) and observe if the JSON response reflects this payload without escaping.",
                ],
                "token": [account.get("token")],
                "path": [get_endpoint],
                "expected_response_code": [
                    "200 OK if the JSON response properly escapes or removes the malicious payload.",
                    "400 Bad Request if the input is rejected due to validation rules."
                ],
                "security": [
                    "Verify that JSON responses properly escape all user inputs to prevent XSS vulnerabilities.",
                    "Ensure that malicious scripts in parameters are not reflected in the response."
                ]
            }

            # This prompt tests if JSON responses are properly escaped, ensuring no XSS vulnerabilities when displaying data to users.
            ,
            # Inspect Headers and Metadata for XSS Protections
            {
                "objective": "Inspect Headers and Metadata for XSS Protections",
                "steps": [
                    f"Send a GET request to {get_endpoint}.",
                ],
                "path": [get_endpoint],
                "token": [account.get("token")],
                "expected_response_code": [
                    "200 OK with headers such as Content-Security-Policy and X-XSS-Protection properly set."
                ],
                "security": [
                    "Inspect the response headers for security settings such as Content-Security-Policy, X-XSS-Protection, and others to verify if XSS protections are enabled."
                    "Ensure that the API response headers contain adequate security settings to mitigate XSS risks.",
                    "Verify that the Content-Security-Policy header is configured to prevent inline scripts or unauthorized domains from executing scripts."
                ]
            }

            # This prompt checks if appropriate security headers are set to protect against XSS vulnerabilities.
        ]

        return prompts

    def test_csrf(self, endpoint, schema, prompts, method="POST"):
        if method == "POST":
            prompts = prompts + [
                # Test for CSRF Protection in Sensitive Actions
                {
                    "objective": "Test for CSRF Protection in Sensitive Actions",
                    "steps": [
                        f"Send a POST request to {endpoint}  based on schema {schema}(e.g., account update or password change) without including any authentication tokens (e.g., CSRF token or session cookie).",
                    ],
                    "token": [""],
                    "path": [endpoint],
                    "expected_response_code": [
                        "403 Forbidden if CSRF protection is correctly enforced and the request lacks proper tokens.",
                        "401 Unauthorized if authentication is required and missing."
                    ],
                    "security": [
                        "Observe the API's response to determine if the request is rejected due to missing tokens."
                        "Ensure that the API requires authentication tokens for sensitive actions to mitigate CSRF attacks.",
                        "Verify that the absence of a CSRF token results in a proper rejection of the request."
                    ]
                }

                # This prompt tests if the API protects sensitive actions by requiring proper authentication tokens.
                ,  # Test for CSRF Token Requirement
                {
                    "objective": "Test for CSRF Token Requirement",
                    "steps": [
                        f"Send a POST request to {endpoint} based on schema {schema} with valid session cookies but without including a CSRF token.",
                    ],
                    "token": [""],
                    "path": [endpoint],
                    "expected_response_code": [
                        "403 Forbidden if the API correctly requires a CSRF token for the action.",
                        "400 Bad Request if the request format is invalid or missing required headers."
                    ],
                    "security": [
                        "Check if the API rejects the request, indicating that CSRF tokens are mandatory for protected actions."
                        "Confirm that CSRF tokens are required for all sensitive actions and that their absence results in the rejection of requests.",
                        "Ensure that proper error messages are returned without exposing sensitive system details."
                    ]
                }

                # This prompt verifies if the API requires a CSRF token, ensuring protection against CSRF attacks.
                ,  # Test for CSRF Token Validation
                {
                    "objective": "Test for CSRF Token Validation",
                    "steps": [
                        f"Send a POST request to {endpoint} based on schema {schema} with valid session cookies but an incorrect or expired CSRF token.",
                    ],
                    "path": [endpoint],
                    "token": [self.create_random_bearer_token()],
                    "expected_response_code": ["403 Forbidden if the CSRF token is invalid or expired.",
                                               "401 Unauthorized if the session cookies are also invalid or missing."],
                    "security": [
                        "Verify if the API rejects the request, indicating that the provided CSRF token is invalid.",
                        "Ensure that the API validates the CSRF token correctly, rejecting requests with invalid or expired tokens.",
                        "Verify that error messages do not reveal sensitive information about the token validation process."]}

                # This prompt tests if the API validates the CSRF token, ensuring only valid tokens are accepted.
                , ]
        elif method == "GET":
            prompts = prompts + [
                # Test CSRF Protection in GET Requests

                {
                    "objective": "Test CSRF Protection in GET Requests",
                    "steps": [
                        f"Send a GET request to {endpoint} to retrieve sensitive data (e.g., personal information) without including a CSRF token or session cookie.",
                    ],
                    "token": [""],
                    "path": [endpoint],
                    "expected_response_code": [
                        "401 Unauthorized if authentication is required but missing.",
                        "403 Forbidden if the API enforces CSRF protection for sensitive GET requests."
                    ],
                    "security": [
                        "Observe the response to check if the API enforces CSRF protection or authentication for GET requests with sensitive data.",
                        "Confirm that the API applies CSRF protection or requires authentication for GET requests that handle sensitive data.",
                        "Ensure that unauthorized access attempts do not result in any sensitive data exposure."
                    ]
                }
            ]

            return prompts

    def test_buisness_logic(self, endpoint, schema, account, prompts, method="POST"):
        if method == "POST":
            prompts.append(
                # Test for Unauthorized Access Through Business Logic
                {
                    "objective": "Test for Unauthorized Access Through Business Logic",
                    "steps": [
                        f"Send a POST request to {endpoint} based on schema {schema} with manipulated data, such as setting an unauthorized discount or modifying the item price with user:{account}.\n",
                    ],
                    "path": [endpoint],
                    "token": [account.get("token")],
                    "expected_response_code": [
                        "403 Forbidden if the API correctly identifies and prevents unauthorized actions.",
                        "400 Bad Request if the input data violates business rules or constraints."
                    ],
                    "security": [
                        "Verify if the API prevents the manipulated changes from being applied and restricts unauthorized actions.",
                        "Ensure the API enforces proper validation and checks on critical business logic operations to prevent unauthorized manipulations.",
                        "Verify that manipulated requests do not bypass security measures or result in unauthorized actions."
                    ]
                }

                # This prompt tests for flaws in the business logic that could allow unauthorized discounts or price manipulations.
            )
        elif method == "GET":
            prompts.append(
                # Test for Data Exposure via Business Logic Flaws
                {
                    "objective": "Test for Data Exposure via Business Logic Flaws",
                    "steps": [
                        f"Send a GET request to {endpoint} as a low-privilege user:{account}.\n",

                    ],
                    "path": [endpoint],
                    "token": [account.get("token")],
                    "expected_response_code": [
                        "403 Forbidden if the user lacks permission to access the requested data.",
                        "200 OK only if the user is authorized to access the data."
                    ],
                    "security": [
                        "Attempt to retrieve sensitive information that should not be accessible to the user.",
                        "Verify if the API enforces permission checks to restrict access to data beyond the user's allowed level."
                        "Ensure the API applies strict access controls to sensitive data based on user permissions.",
                        "Verify that unauthorized access attempts are logged and handled securely."
                    ]
                }

                # This prompt tests if the business logic prevents unauthorized access to sensitive user data.
            )

        return prompts

    def test_roles(self, post_endpoint, schema, account, prompts):
        prompts.append(
            # Test for Manipulation of User Roles
            {
                "objective": "Test for Manipulation of User Roles",
                "steps": [
                    f"Send a POST request to {post_endpoint} based on schema {schema} attempting to elevate a standard user's role to an admin.",
                ],
                "token": [account.get("token")],
                "path": [post_endpoint],
                "expected_response_code": [
                    "403 Forbidden if the API correctly identifies and prevents role escalation attempts.",
                    "400 Bad Request if the request format or parameters are invalid."
                ],
                "security": [
                    "Verify if the API prevents unauthorized role manipulations.",
                    "Ensure that the API enforces strict role-based access controls and prevents unauthorized role changes.",
                    "Verify that unauthorized role manipulation attempts are logged and do not expose any vulnerabilities."
                ]
            }

            # This prompt tests if the API prevents unauthorized role escalation.
        )
        return prompts

    def test_limiting(self, request, endpoint, prompts, key=None):
        if key:

            prompts.append(

                # Check for Lack of Resources & Rate Limiting
                {
                    "objective": "Check for Lack of Resources & Rate Limiting",
                    "steps": [
                        f"Send a GET request to {endpoint}.",

                    ],
                    "path": [endpoint],
                    "token": [key],
                    "expected_response_code": [
                        "429 Too many requests"
                    ],
                    "security": [
                        "Ensure each step is followed without skipping to maintain the integrity of the test.",
                        "Check for HTTP 429 response to confirm if rate limiting is enforced after numerous sequential OTP verification attempts.",
                        "Assess server response under load for stability and consistency to prevent denial of service.",
                        "Review the application logs to ensure that all brute force attempts are recorded for security monitoring.",
                        "Implement rate limiting on sensitive actions like OTP verification to mitigate brute-force attacks."
                    ]
                }

                # This prompt tests if security headers are properly configured to prevent exposure to security risks.
            )
        else:
            prompts = prompts + [
                # Test Rate-Limiting for Abuse Prevention
                {
                    "objective": "Test Rate-Limiting for Abuse Prevention",
                    "steps":
                        request

                    ,
                    "expected_response_code": [
                        "429 Too Many Requests if the API correctly enforces rate-limiting.",
                        "200 OK for requests that fall within the allowed rate limit."
                    ],
                    "path": [endpoint] * 10,
                    "token": [""] * 10,
                    "security": [
                        "Monitor the responses to verify if the API enforces a rate limit after a specific number of requests.",
                        "Check if the API responds with a 429 Too Many Requests status when the rate limit is exceeded."
                        "Ensure that the rate-limiting mechanism effectively prevents abuse while allowing legitimate users to access the API without disruption.",
                        "Verify that rate-limiting thresholds and error messages do not expose sensitive implementation details."
                    ]
                }

                # This prompt tests if the API has adequate rate-limiting to prevent abuse.
            ]
        return prompts

    def test_throttling(self, prompts):
        resource_intensive_endpoints = self.get_correct_endpoints_for_method("resource_intensive_endpoint", "GET")
        for resource_intensive_endpoint, _, _ in resource_intensive_endpoints:
            if "id}" in resource_intensive_endpoint:
                resource_intensive_endpoint = self.replace_placeholders_with_1(resource_intensive_endpoint, 1)
            one = [
                      f"Send a series of GET requests per second to the endpoint {resource_intensive_endpoint} for 30 seconds and verify that all requests return a 200 OK response."] * 10
            hundert = [
                          f"Send a burst of 100 GET requests per second to the endpoint {resource_intensive_endpoint} for 30 seconds and observe the API's response."] * 20
            ten_status = ["200 OK for all legitimate requests under normal traffic conditions.", ] * 10
            hundert_status = [
                                 "429 Too Many Requests if throttling is applied when excessive requests are detected."] * 20

            paths = [resource_intensive_endpoint] * 30
            tokens = [""] * 30

            prompts.append(

                # Test Throttling for Denial-of-Service (DoS) Attack Prevention

                {
                    "objective": "Test Throttling for Denial-of-Service (DoS) Attack Prevention",
                    "steps": [
                        one,
                        hundert,
                        f"Analyze the API's response during the excessive traffic burst. Check for status codes such as 429 Too Many Requests or 503 Service Unavailable, indicating that throttling is applied.",
                        f"4: Reduce the request rate back to 10 GET requests per second to {resource_intensive_endpoint} and verify that legitimate traffic returns a 200 OK response, confirming the system has recovered."
                    ],
                    "expected_response_code": [ten_status,
                                               hundert_status,
                                               "503 Service Unavailable if the server temporarily denies access due to heavy load.",
                                               "4: 200 OK for legitimate requests after the request rate returns to normal."
                                               ],
                    "path": paths,
                    "token": tokens,
                    "security": [
                        "Ensure that the API's throttling mechanism effectively prevents DoS attacks by limiting excessive traffic.",
                        "Verify that throttling does not unintentionally block or degrade service for legitimate users.",
                        "Confirm that the API recovers quickly and reliably after excessive traffic subsides, maintaining availability for normal traffic."
                    ]
                }

                # This prompt tests if the API prevents DoS attacks through request throttling.
            )

            return prompts

    def generate_user(self, post_account, counter, prompts):
        for account in post_account:
            account_path = account.get("path")
            account_schema = account.get("schema")
            if self.config.get("name") == "crapi":
                account_user = self.create_account(login_schema=account_schema, login_path=account_path)


            else:
                account_user = self.get_credentials(account_schema, account_path, new_user=True).get("example")
            if account_user is None:
                continue
            account_user["x"] = counter
            if "api" in account_path:
                parts = [api for api in account_path.split("/") if api.strip()]
                api = [part for part in parts if part.startswith("api")]
                api = api[0]
                account_user["api"] = api
            if self.config.get("name") == "vAPI":
                text = f'{account_user.get("username")}:{account_user.get("password")}'

                account_user["token"] = base64.b64encode(text.encode()).decode()

            prompt = {
                "objective": "Setup tests",
                "steps": [
                    f"Create an account by sending a POST HTTP request to the correct endpoint from this {account_path} with these credentials of user:{account_user}.\n"
                    f"Request body should be in application/json and look similar to this: {{ {account_user}}}"],
                "expected_response_code": ["200 OK", "201 Created"],
                "token": [""],
                "path": [account_path],
                "security": [
                    "Ensure that the correct expected code is received  confirming that access is restricted and no sensitive data is included in the response body."]
            }

            self.accounts.append(account_user)
            prompts = prompts + [prompt]
            counter = counter + 1

        return prompts, counter

    def replace_ids(self, account, endpoint, given_id=None):

        if given_id is None:
            id = account.get("id", 1)
        else:
            id = given_id
        other_id = self.get_other_id(id, account)

        new_endpoint = endpoint.replace("{id}", str(id))
        endpoint_of_other_user = endpoint.replace("{id}", str(other_id))

        # Handle {id}
        if "{id}" in endpoint:
            if "example" in account and "id" in account["example"]:
                id = account["example"]["id"]
                other_id = id - 1 if account == self.accounts[-1] else id + 1
                new_endpoint = endpoint.replace("{id}", str(id))
                endpoint_of_other_user = endpoint.replace("{id}", str(other_id))
            else:

                new_endpoint = endpoint.replace("{id}", str(id))
                endpoint_of_other_user = endpoint.replace("{id}", str(other_id))
        # Handle _id mostly for resources
        elif "_id}" in endpoint:
            key_found, key = self.key_in_path(endpoint, self.resources)
            if key_found == True and key is not None:
                key = str(key)
                first_id = self.resources[key][0]
                if len(self.resources[key]) > 1:
                    second_id = random.choice(self.resources[key][1:])
                else:
                    second_id = 1  # fallback to same id if no other id available
                new_endpoint = endpoint.replace("{", "").replace("}", "").replace(key, first_id)
                endpoint_of_other_user = endpoint.replace("{", "").replace("}", "").replace(key, second_id)
            else:
                other_id = self.get_other_id(id, account)
                new_endpoint = self.replace_id_placeholder(endpoint, str(id))
                endpoint_of_other_user = self.replace_id_placeholder(endpoint, str(other_id))

            if given_id is not None:
                other_id = self.get_other_id(id, account)
                new_endpoint = self.replace_id_placeholder(endpoint, str(given_id))
                endpoint_of_other_user = self.replace_id_placeholder(endpoint, str(other_id))

        return new_endpoint, endpoint_of_other_user

    def get_other_id(self, id, account):
        if str(id).isdigit():

            other_id = id - 1 if account == self.accounts[-1] else id + 1
        else:
            current_index = self.accounts.index(account)

            # Pick next account if not last, else pick previous
            other_account = self.accounts[current_index + 1] if current_index < len(self.accounts) - 1 else \
                self.accounts[current_index - 1]

            other_id = other_account.get("id", 1)
        if other_id is None:
            other_id = 2


        return other_id

    def get_file(self, param):
        # Get current file directory
        current_dir = os.path.dirname(__file__)

        # Go up one level
        parent_dir = os.path.abspath(os.path.join(current_dir, ".."))
        parent_dir = parent_dir.split("/src")[0]

        # Search for file (glob is recursive-friendly)
        file = glob.glob(os.path.join(parent_dir, param), recursive=True)

        if not file or param == "":
            return "Not found"
        return file

    def get_path_and_schema(self, login):
        login_path = login.get("path")
        login_schema = login.get("schema")
        if "example" not in login_schema:
            login_schema = self.adjust_schema_with_examples(login_schema)
        login_schema = login_schema.get("example")

        return login_path, login_schema
